I am embedding my command line application into a ncurses-TUI.
My application (client/server) should be able to print a lot lines if needed, but it must stays into the windows I defined :
/* Removed code */
ITEM **my_items;
int c;
MENU *my_menu;
WINDOW *my_menu_win;
int n_choices, i;
// Initialize curses
initscr(); // initializes the screen
start_color();
cbreak();
noecho();
keypad(stdscr, TRUE);
init_pair(1, COLOR_RED, COLOR_BLACK);
/* Removed code */
/* Create items */
n_choices = ARRAY_SIZE(choices);
my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
for(i = 0; i < n_choices; ++i)
{
my_items[i] = new_item(choices[i], choices[i]);
}
/* Removed code */
/* Create menu */
my_menu = new_menu((ITEM **)my_items);
/* Set menu option not to show the description */
menu_opts_off(my_menu, O_SHOWDESC);
/* Create the window to be associated with the menu */
my_menu_win = newwin(WIN_HEIGHT, WIN_WIDTH, WIN_YPOS, WIN_XPOS);
keypad(my_menu_win, TRUE);
/* Set main window and sub window */
set_menu_win(my_menu, my_menu_win);
set_menu_sub(my_menu, derwin(my_menu_win, WIN_HEIGHT/2, WIN_WIDTH/2, WIN_HEIGHT/2-3, WIN_WIDTH/2-10));
/* Set menu mark to the string " * " */
set_menu_mark(my_menu, ">");
/* Print a border around the main window and print a title */
box(my_menu_win, 0, 0);
/* Removed code */
/* Post the menu */
post_menu(my_menu);
wrefresh(my_menu_win);
endwin(); //resets the screen
}
1 How can I add a windows inside this windows with a scrolling content where all the output that usually goes to the terminal would be print
2 ...or is it possible to link that windows with the terminal output ?
Related
I'm having a hard time understanding the problem with a window in ncurses. I created a layout of several windows and want to have a function that will border a window. Look like this:
int main() {
use_env(TRUE);
initscr();
start_color();
cbreak();
noecho();
curs_set(0);
WINDOW *win_corner = newwin(WCLINES, WCCOLS, WCX, WCY);
choose_lvl(win_corner);
...
}
int choose_lvl(WINDOW *win) {
box(win, 0, 0);
wrefresh(win);
refresh();
int c, curr_option = 0;
init_pair(1, COLOR_CYAN, COLOR_BLACK);
attron(COLOR_PAIR(1));
mvwprintw(win, 1, 1, "Choose your level");
...
}
It seems like box() doesnt have any effect at all - what could it be? My current theory is to suppose something wrong with the coordinates of the window.
refresh() refreshes the updates on stdscr. newwin() creates an independant window. A refresh on stdscr does not update the alternate window. The same without refresh() in choose_lvl() function would work fine as you would force update only on the alternate window.
You can also create a sub-window of stdscr with subwin() to make refresh() update the whole hierarchy:
#include <unistd.h>
#include <curses.h>
#define WCLINES 10
#define WCCOLS 80
#define WCX 4
#define WCY 4
int choose_lvl(WINDOW *win) {
box(win, 0, 0);
//wrefresh(win);
//refresh();
int c, curr_option = 0;
init_pair(1, COLOR_CYAN, COLOR_BLACK);
attron(COLOR_PAIR(1));
mvwprintw(win, 1, 1, "Choose your level");
refresh();
return 0;
}
int main() {
use_env(TRUE);
initscr();
start_color();
cbreak();
noecho();
curs_set(0);
//WINDOW *win_corner = newwin(WCLINES, WCCOLS, WCX, WCY);
WINDOW *win_corner = subwin(stdscr, WCLINES, WCCOLS, WCX, WCY);
choose_lvl(win_corner);
// quick&dirty pause to suspend program execution
// right after the windows display
pause();
return 0;
}
Execution:
$ gcc win.c -lncurses
$ ./a.out
The result is:
I'm using Win32 API. This is just a very simple rendering of a rectangle. There are two screen buffers which I just swap alternately to display every next frame. Every time I run the program, I see horizontal flickers. I haven't tried this on any other device so I'm not really sure if you will be able see it too but if you do then perhaps you can show me some ways to get rid of it.
#include <stdio.h>
#include <string.h>
#include <windows.h>
HANDLE create_screen_buffer(SHORT height, SHORT width);
int main(void)
{
enum { SCREENS = 2 }; /* number of screen buffers */
HANDLE screen[SCREENS]; /* console screen buffers */
HANDLE next_screen;
int screen_index = 0;;
COORD screen_origin = { 0, 0 }; /* top-left corner of screen */
DWORD chars_written; /* used in `WriteConsole()` */
int i, j, row; /* loop counters */
enum { MAP_HEIGHT = 30, MAP_WIDTH = 70 };
/* this is where you prepare stuff before rendering to the screen */
char map[MAP_HEIGHT][MAP_WIDTH];
/* initialize screen buffers */
for (i = 0; i < SCREENS; ++i)
{
screen[i] = create_screen_buffer(MAP_HEIGHT, MAP_WIDTH);
if (screen[i] == NULL)
{
printf("ERROR: Failed to load screen buffers.\n");
/* free any previously loaded screen buffers */
for (j = 0; j < i; ++j)
CloseHandle(screen[j]);
}
}
/* initialize map */
for (i = 0; i < MAP_HEIGHT; ++i)
memset(map[i], '*', MAP_WIDTH);
for (i = 0; i < 200; ++i)
{
next_screen = screen[screen_index];
/* start writing from the top-left corner */
SetConsoleCursorPosition(next_screen, screen_origin);
/* write the map to the next frame */
for (row = 0; row < MAP_HEIGHT; ++row)
{
WriteConsoleA(next_screen, map[row], MAP_WIDTH, &chars_written, NULL);
WriteConsoleA(next_screen, "\n", 1, &chars_written, NULL);
}
/* display the next frame */
SetConsoleActiveScreenBuffer(next_screen);
/* set the next screen */
screen_index ^= 1;
/* just a little delay for more steady framerate */
Sleep(1);
}
/* free all screen buffers */
for (i = 0; i < SCREENS; ++i)
CloseHandle(screen[i]);
/* (optional) show the standard output */
SetConsoleActiveScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE));
return 0;
}
HANDLE create_screen_buffer(SHORT height, SHORT width)
{
HANDLE screen;
COORD size;
CONSOLE_CURSOR_INFO cci;
screen = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE, /* read/write access */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* shared */
NULL, /* default security attributes */
CONSOLE_TEXTMODE_BUFFER, /* must be TEXTMODE */
NULL /* reserved, must be NULL */
);
if (screen == NULL)
return NULL;
size.X = width + 1;
size.Y = height + 1;
SetConsoleScreenBufferSize(screen, size);
/* hide the text cursor */
GetConsoleCursorInfo(screen, &cci);
cci.bVisible = FALSE;
SetConsoleCursorInfo(screen, &cci);
return screen;
}
My laptop is Macbook Pro.
I installed libxcb on it and tried a simple example that x.org given:
#include <unistd.h> /* pause() */
#include <xcb/xcb.h>
int main ()
{
xcb_connection_t *c;
xcb_screen_t *screen;
xcb_window_t win;
/* Open the connection to the X server */
c = xcb_connect (NULL, NULL);
/* Get the first screen */
screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
/* Ask for our window's Id */
win = xcb_generate_id(c);
/* Create the window */
xcb_create_window (c, /* Connection */
XCB_COPY_FROM_PARENT, /* depth (same as root)*/
win, /* window Id */
screen->root, /* parent window */
0, 0, /* x, y */
150, 150, /* width, height */
10, /* border_width */
XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */
screen->root_visual, /* visual */
0, NULL); /* masks, not used yet */
/* Map the window on the screen */
xcb_map_window (c, win);
/* Make sure commands are sent before we pause, so window is shown */
xcb_flush (c);
pause (); /* hold client until Ctrl-C */
return 0;
}
But there is no window shown on screen. Is there something I forget?
This question already has answers here:
"Multiple definition", "first defined here" errors
(6 answers)
Closed 5 years ago.
I am running a program which makes use of the ncurses library to display windows in the terminal containing data being updated and inserted into its corresponding window from my main source file.
I have a separate file with its own header file which contains printf statements I would like to convert to ncurse functions. And display within the windows I created.
ncurses required some setup and made use of some small functions so im unsure how to use it within both files. I tried including it within my header file and linking to both my source files however I get multiple defenitions, first defined here errors.
Setup for ncurse windows within my main file:
/* Window defintion constants*/
#define PROTOPORT 36795 /* default protocol port number, booknumber */
#define QLEN 6 /* size of request queue */
#define MAXSIZE 256
#define NUMWINS 7
#define RES_BUF_SIZE 80
WINDOW *w[NUMWINS];
WINDOW *sw[NUMWINS];
WINDOW wh[NUMWINS];
void update_win(int i) {
touchwin(w[i]);
wrefresh(sw[i]);
}
/* add string to a window */
void wAddstr(int z, char c[255]);
void GUIshutdown(char * response) {
wmove(sw[4], 0, 0);
wclrtoeol(sw[4]);
wprintw(sw[4], "All finished. Press Enter to terminate the program.");
update_win(4);
wgetstr(sw[4], response);
/* End screen updating */
endwin();
echo();
}
//////////
int main(int argc, char *argv[]) {
/***********************************************/
/* setup ncurses for multiple windows */
/***********************************************/
setlocale(LC_ALL, ""); // this has to do with the character set to use
initscr();
cbreak();
noecho();
nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
/* Clear screen before starting */
clear();
w[0] = newwin(0,0,0,0);
if (LINES != 43 || COLS != 132) {
move(0, 0);
addstr("Piggy3 requires a screen size of 132 columns and 43 rows");
move(1, 0);
addstr("Set screen size to 132 by 43 and try again");
move(2, 0);
addstr("Press enter to terminate program");
mvprintw(3,0,"%dx%d\n", COLS, LINES);
refresh();
getstr(response); // Pause so we can see the screen
endwin();
exit(EXIT_FAILURE);
}
/* create the 7 windows and the seven subwindows*/
for (a = 0; a < NUMWINS; a++) {
w[a] = newwin(WPOS[a][0], WPOS[a][1], WPOS[a][2], WPOS[a][3]);
sw[a] = subwin(w[a], WPOS[a][0] - 2, WPOS[a][1] - 2, WPOS[a][2] + 1, WPOS[a][3] + 1);
scrollok(sw[a], TRUE); // allows window to be automatically scrolled
wborder(w[a], 0, 0, 0, 0, 0, 0, 0, 0);
touchwin(w[a]);
wrefresh(w[a]);
wrefresh(sw[a]);
}
/***********************************************/
/* Windows */
/***********************************************/
/*
* Notes:
* sw[0] = upper left window,
* sw[1] = upper right window,
* sw[2] = bottom left window,
* sw[3] = bottom right window
* sw[4] = bottom command window
* sw[5] = bottom inputs window
* sw[6] = bottom errors menu.
*/
wmove(sw[0], 0, 0);
wprintw(sw[0], "This is the window where the data flowing from left to right ");
wprintw(sw[0], "will be displayed. Notice now we don't need to worry about when we reach the last ");
wprintw(sw[0], " position in the subwindow, we will just wrap around down to the next line of the subwindow");
wprintw(sw[0], " and can never mess up the border that is in the parent window");
wprintw(sw[inLeft], " Data coming from the left, head piggy\n");
wmove(sw[1], 4, 0);
waddstr(sw[1], "Data leaving right side");
wmove(sw[2], 4, 0);
waddstr(sw[2], "Data leaving the left side");
wmove(sw[3], 4, 0);
waddstr(sw[3], "Data arriving from the right");
wmove(sw[4], 0, 0);
waddstr(sw[4], "Commands: ");
wmove(sw[5], 0, 0);
waddstr(sw[5], "Data Entry: ");
wmove(sw[6], 0, 0);
waddstr(sw[6], "Errors: ");
for (int a = 0; a < NUMWINS; a++){
update_win(a);
}
wmove(sw[4], 0, 0);
wprintw(sw[4], "Press Enter to see the output in the upper left window scroll");
wgetstr(sw[4], response); // Pause so we can see the screen
wmove(sw[4], 0, 0);
wclrtoeol(sw[4]); // clears current line without clobbering borders
update_win(4);
}
You need header guards in your .h files.
#ifndef HEADER_FILE_NAME_H
#define HEADER_FILE_NAME_H
// include,definitions..
#endif //HEADER_FILE_NAME_H
I'm writing a program that shows some information on screen and I want them to be updated each second.
What should I do?
I'm writing a C console application on Windows.
The Pianist, you can work with a console using WinAPI functions.
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (!hConsole)
return;
After that determine the cursor position:
CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
GetConsoleScreenBufferInfo(hConsole, &csbi);
COORD coordCur = csbi.dwCursorPosition;
And...
while (TRUE) { // your cycle goes here
// ...
// now you can change position of the cursor
coordCur.X = newX;
coordCur.Y = newY;
SetConsoleCursorPosition(hConsole, coordCur);
// and print any information from the new position
printf("..."); // old text will be replaced
}
So you don't need to clear and refresh all console if you want to change a small piece of text.
ps. Don't forget to release a handle:
CloseHandle(hConsole);
There's a KB article on that topic.
Two options:
Write a function that will programmatically clear the screen
/* Standard error macro for reporting API errors */
#define PERR(bSuccess, api){if(!(bSuccess)) printf("%s:Error %d from %s \
on line %d\n", __FILE__, GetLastError(), api, __LINE__);}
void cls( HANDLE hConsole )
{
COORD coordScreen = { 0, 0 }; /* here's where we'll home the
cursor */
BOOL bSuccess;
DWORD cCharsWritten;
CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */
DWORD dwConSize; /* number of character cells in
the current buffer */
/* get the number of character cells in the current buffer */
bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );
PERR( bSuccess, "GetConsoleScreenBufferInfo" );
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
/* fill the entire screen with blanks */
bSuccess = FillConsoleOutputCharacter( hConsole, (TCHAR) ' ',
dwConSize, coordScreen, &cCharsWritten );
PERR( bSuccess, "FillConsoleOutputCharacter" );
/* get the current text attribute */
bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );
PERR( bSuccess, "ConsoleScreenBufferInfo" );
/* now set the buffer's attributes accordingly */
bSuccess = FillConsoleOutputAttribute( hConsole, csbi.wAttributes,
dwConSize, coordScreen, &cCharsWritten );
PERR( bSuccess, "FillConsoleOutputAttribute" );
/* put the cursor at (0, 0) */
bSuccess = SetConsoleCursorPosition( hConsole, coordScreen );
PERR( bSuccess, "SetConsoleCursorPosition" );
return;
}
Use a system function (not very pretty; requires starting a shell and a command)
system("cls");
Since you are on Windows, you can do this:
system('cls')
Here is an example:
#include <stdio.h>
int main()
{
printf("Press enter to clear the screen.");
getchar();
system("cls");
return 0;
}
If you are developing using Microsoft Visual Studoo and you want to programmatically clear the screen by outputting spaces, see Example 2 at http://msdn.microsoft.com/en-us/library/windows/desktop/ms682022(v=vs.85).aspx.
If you had searched google before asking, you would have found this link right in the first results.
To quote one of the methods:
Windows:
#include <windows.h>
void ClearScreen()
{
HANDLE hStdOut;
CONSOLE_SCREEN_BUFFER_INFO csbi;
DWORD count;
DWORD cellCount;
COORD homeCoords = { 0, 0 };
hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
if (hStdOut == INVALID_HANDLE_VALUE) return;
/* Get the number of cells in the current buffer */
if (!GetConsoleScreenBufferInfo( hStdOut, &csbi )) return;
cellCount = csbi.dwSize.X *csbi.dwSize.Y;
/* Fill the entire buffer with spaces */
if (!FillConsoleOutputCharacter(
hStdOut,
(TCHAR) ' ',
cellCount,
homeCoords,
&count
)) return;
/* Fill the entire buffer with the current colors and attributes */
if (!FillConsoleOutputAttribute(
hStdOut,
csbi.wAttributes,
cellCount,
homeCoords,
&count
)) return;
/* Move the cursor home */
SetConsoleCursorPosition( hStdOut, homeCoords );
}