I have a the following piece of code using ncurses. I would like to know whether I can use a single move function to print a few lines.
For Example:
move(25,25);
printw("Line 1\n");
printw("Line 2\n");
Line 1 prints at (25,25) location but Line 2 prints at (26,0) if I don't use move(26,25). Can I avoid the second move and still print Line 2 at (26,25)????
You can define a new window if what you want to print has to be aligned. Shortly :
#include <ncurses.h>
int main()
{
WINDOW* mywin;
initscr();
cbreak();
keypad(stdscr, TRUE);
int height=15;
int width=30;
int starty=25;
int startx=25;
printw("F9 to exit");
refresh();
mywin = newwin(height, width, starty, startx);
mvwprintw(mywin,0,0,"First line\n");
wprintw(mywin,"Second line");
wrefresh(mywin);
while(getch() != KEY_F(9)) {}
endwin();
return 0;
}
If this approach does not fit, then you'll have to move manually to next position you want to print.
Related
I have a couple of ncurses windows and am trying to move the cursor, to the end of the current line of text.
In other words, I want to move to the first non-blank character from the end of the window.
Example:
If I have a line of text in a ncurses window
I need help! Please! !
^
|
cursor
I want to move the cursor last character
I need help! Please! !
^
|
cursor
My best attempt is this:
#include <ncurses.h>
int main()
{
initscr();
refresh();
WINDOW* w = newwin(100, 100, 0, 0);
wprintw(w, "I need help! Please! !");
wmove(w, 0, 3);
wrefresh(w);
// MY ATTEMPT
int maxX, maxY, x, y;
getmaxyx(w, maxY, maxX);
getyx(w, y, x);
wmove(w, y, maxX);
while (winch(w) == ' ') {
wmove(w, y, maxX-1);
}
wrefresh(w);
// END OF MY ATTEMPT
getch();
delwin(w);
endwin();
return 0;
}
Which I think is logically sound, but is not working, and I am not sure why (the position of cursor isn't changing at all)
How do I do this? Is there an easy way I am missing? Why is my solution not working?
You never update your x position inside the loop, so you repeatedly move to one before the right edge of your window.
Assuming you do not use maxX elsewhere, simply pre-decrement it within the loop.
while((winch(w) & A_CHARTEXT) == ' ') {
wmove(w, y, --maxX);
}
Note that you should also use the A_CHARTEXT bit mask to extract the char from a chtype.
A very rough example of your method working, using stdscr:
#include <ncurses.h>
int main(void) {
initscr();
noecho();
cbreak();
while (1) {
clear();
mvprintw(10, 5, "Hello world");
move(0, 0);
int my,mx;
getmaxyx(stdscr, my, mx);
move(10, mx);
while ((inch() & A_CHARTEXT) == ' ')
move(10, --mx);
refresh();
napms(100);
}
endwin();
}
I use Xshell to connect to a remote host and write ncurse programs. But it was found that the characters could not be printed in a cycle to the right.
#include <ncurses.h>
int main() {
initscr();
for (int i = 0;i < 10; i++){
addch('o');
}
refresh();
getch();
endwin();
return 0;
}
Result:
Only the first character is printed.
In order to print it all out, I had to add the refresh code
for (int i = 0; i < 10;i++) {
addch('o');
refresh();//print all 'o'
}
I think the BIG problem makes the box function unavailable, because the two Horizontal line of a box are not completed, it only have the first '-' too.
int main() {
initscr();
curs_set(0);
WINDOW *win;
win = newwin(10, 40, 9, 20);
box(win, 0, 0);
refresh();
wrefresh(win);
getch();
endwin();
return 0;
}
Result:
Notice the two horizontal lines up and down
I can't figure out this problem.
2021.3.11
I have I have identified the problem. The problem is with Xshell. I connect my host by Alibaba Cloud Server official website, and the program have no problem. But I still don't konw how to set up my xshell.
Using the following code (save to test.c and compile with gcc -o test test.c -lncurses) I can draw a border, put text inside it, and also put text in the main window.
#include <ncurses.h>
// Print the character 'ch' in the window
// 'win', and do this 'repeat' times.
int print_chars(WINDOW *win, char ch, int repeat) {
if (win == NULL) {
// Print to main window
for (int i=0; i<repeat; i++) {
addch(ch);
refresh();
}
} else {
// Print to the named window
for (int i=0; i<repeat; i++) {
waddch(win, ch);
}
wrefresh(win);
}
return 0;
}
int main(int argc, char **argv)
{
WINDOW *border_win, *win;
initscr();
refresh(); // This seems to be needed;
// I don't know why.
// Create a window to show the border
border_win = newwin(10,40,9,20);
box(border_win,0,0);
wrefresh(border_win);
// Create a window inside that, which
// we will write in. Otherwise it
// seems we will overwrite the border.
win = newwin(8,38,10,21);
print_chars(win, 'a', 10);
// Write something in the main window
// as well, just to show it works
print_chars(NULL, 'o', 10);
getch();
endwin();
return 0;
}
I was wondering if anyone would know how I can modify the following code to allow me to wait for a text entry to be entered, to store it in the corresponding variable and to jump to the next line immediately below it without deleting what was written before except when the size of the window created is exceeded.
#include <curses.h>
int main()
{
WINDOW *wnd;
char txt[100];
// INICIALIZACIÓN DE LAS VENTANAS.
initscr();
cbreak();
noecho();
refresh();
start_color();
init_pair(1,COLOR_WHITE,COLOR_RED);
wnd = newwin(10,100,1,1);
wattron(wnd,COLOR_PAIR(1));
wbkgd(wnd,COLOR_PAIR(1) | ' ');
wclear(wnd);
box(wnd,ACS_VLINE,ACS_HLINE);
wmove(wnd,1,1);
wprintw(wnd,">> ");
wrefresh(wnd);
wmove(wnd,1,6);
echo();
wgetstr(wnd,txt);
noecho();
return 0;
}
What I have programmed right now as soon as it detects the first intro stores the value in char but closes the ncurses window...
Does anyone know how I can fix it to get what I'm looking for?
You need some loop around wgetstr(). So, ignoring what kind of logic you want, something like this:
while (<your condition>)
{
wgetstr(window, text);
<do something with the text you read>
}
Are you speaking about scrolling the window when the cursor is at the the bottom of the window ?
#include <ncurses.h> // <-------------- I use ncurses
int main()
{
WINDOW *wnd;
char txt[100];
int line;
// INICIALIZACIÓN DE LAS VENTANAS.
initscr();
cbreak();
noecho();
refresh();
start_color();
init_pair(1,COLOR_WHITE,COLOR_RED);
wnd = newwin(10,100,1,1);
scrollok(wnd, TRUE); // <--------- Allow scrolling
wattron(wnd,COLOR_PAIR(1));
wbkgd(wnd,COLOR_PAIR(1) | ' ');
wclear(wnd);
box(wnd,ACS_VLINE,ACS_HLINE);
line = 1; // <------------- First line in the window
while (1) {
wmove(wnd,line,1);
wprintw(wnd,">> ");
wnoutrefresh(wnd);
doupdate(); // <----- Refresh all the preceding modifications
echo();
wgetstr(wnd,txt);
noecho();
if (line < 8) { // <------- Check bottom of window
line ++;
} else {
box(wnd,COLOR_PAIR(1) | ' ', COLOR_PAIR(1) | ' '); // <--- Clear old box before scrolling
wscrl(wnd, 1); // <------ scroll 1 line up
box(wnd,ACS_VLINE,ACS_HLINE); // <------ Redo the box
}
}
endwin();
return 0;
}
I am experimenting with Curses in C, and for some reason, when I enter a key when running my program the ball changes direction. I have no idea why; could this be a memory leak? I don't know what to try, since I am a beginner to C. Please provide any guidance that you have!
#include <curses.h>
#include <stdbool.h>
typedef struct ball {
unsigned int x;
unsigned int y;
const char shape;
} Ball;
int main() {
initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);
curs_set(FALSE);
nodelay(stdscr, TRUE);
int maxY, maxX;
int pOneGoingRight = TRUE;
int pOneGoingDown = TRUE;
getmaxyx(stdscr, maxY, maxX);
char input;
Ball pOneBall = {0, 0, '*'};
// Ball *pOneBallPtr = &pOneBall;
while (1) {
clear();
getstr(&input);
if (input == 'q')
break;
mvprintw(0, 0, "Max y and x: %d, %d", maxY, maxX);
mvprintw(1, 0, "Ball y and x: %d, %d", pOneBall.y, pOneBall.x);
if (pOneBall.y == 0) pOneGoingDown = TRUE;
else if (pOneBall.y == maxY) pOneGoingDown = FALSE;
if (pOneBall.x == 0) pOneGoingRight = TRUE;
else if (pOneBall.x == maxX) pOneGoingRight = FALSE;
if (pOneGoingRight) pOneBall.x++;
else pOneBall.x--;
if (pOneGoingDown) pOneBall.y++;
else pOneBall.y--;
mvprintw(pOneBall.y, pOneBall.x, &pOneBall.shape);
refresh();
napms(100);
}
endwin();
return 0;
}
Just looking at your code
char input;
Ball pOneBall = {0, 0, '*'};
Okay, so you have an input to hold the key, and then a struct to hold ball data.
Then you call
getstr(&input);
From the manual
The function getstr is equivalent to a series of calls to getch, until a newline or carriage return is received (the terminating character is not included in the returned string). The resulting value is placed in the area pointed to by the character pointer str.
That means that getstr is reading from the keyboard until newline or carriage return is read. There's nothing to stop it from reading 10 characters, or a hundred, and writing them right over the data that follows, being your ball position info.
Use getch if you want to read a single character, or some other method. Since there doesn't seem to be any way to limit how many characters getstr reads, just never use it. Ever.
edit:
try getnstr( &input, 1 ) maybe?
edit-edit:
that will beep on excess characters, which you probably don't want. just change to use getch or something
Just change getstr(&input); by input=getch();
Im trying to do a basic menu in C. I'm supposed to do this with ncurses lib. I was working with this tutorial:
Video On YouTube
But mine version has some problems:
1)The menu will not print properly, it will reveal only while choosing menu items. Then the highlight won't go off
2)Option made on menu won't print on the top
Can you help me? Is that idea of Menu good or should i look for other tutorial (any help ?).
#include <stdio.h>
#include <ncurses.h>
#include <string.h>
#include <menu.h>
int main(int argc, char **argv)
{
int i, c;
char powitanie[]="SLOWNIK UNIWERSALNY";
int szer, dlug; //wartosci dlugosci i szerokosci terminalu
initscr(); //Inizjalizacja całości ncurses, kolory itp
raw();
noecho();
keypad(stdscr, TRUE);
start_color();
//init_pair(1, COLOR_BLUE, COLOR_BLACK); //wybór kolorów
getmaxyx(stdscr, szer, dlug); //pobranie rozmiarów terminalu
move(szer/2, (dlug-strlen(powitanie))/2); //przesuwamy kursor na środek (tak aby się ładnie wydrukowało)
//attron(COLOR_PAIR(1)); //Aktywujemy wybrane kolory
printw(powitanie); //Drukujemy powitanie
//attroff(COLOR_PAIR(1));//Dezaktywujemy kolory
refresh();//Odswiezamy (inaczej się nie wyswietli)
WINDOW * menuwin=newwin(6, dlug-12, szer-8, 6); //Definiujemy i tworzymy 'okno'
box(menuwin, 0, 0);
refresh();//ponownie odświeżamy aby okno się pojawiło
wrefresh(menuwin);//odświeżamy samo okno
keypad(menuwin, TRUE);//umozliwiamy dzialanie klawiatury w oknie
char *opcje[] = {
"Tlumacz z Polskiego na Angielski",
"Tlumacz z Angielskiego na Polski",
"Edystuj slownik",
"Wybierz slownik",
"Wyjdz",
};
int wybor;
int zaznacz=0;
while(1)//cala ta petla sluzy ciaglemu tworzeniu menu z podswietleniem wybranego elementu
{
for(i=0; i<5; i++)
{
if(i==zaznacz)
{
wattron(menuwin, A_REVERSE);
mvwprintw(menuwin, i+1, 1, opcje[i]);
wattroff(menuwin, A_REVERSE);
}
wybor = wgetch(menuwin);
switch(wybor)
{
case KEY_UP:
zaznacz--;
if(zaznacz==-1) zaznacz=0;//zabezpieczenie przed wyjsciem "poza" menu
break;
case KEY_DOWN:
zaznacz++;
if(zaznacz==5) zaznacz=4;
break;
default:
break;
}
if(wybor==10) break;
}
printw("Wybrano:%s", opcje[zaznacz]);
}
return(0);
}
PS: Code comments are not in English but i hope the won't be necessary
There are quite a few problems here. I have included a modified version of your code that works, and I will attempt to describe the changes.
There were some unused variables, namely argc, argv, and c, so I cast these to void in order to silence compiler warnings. You can remove the c and change to int main(void), if you like, removing these variables altogether.
I have added the stdlib.h header file to your #includes for the exit() function. This is used in the new error function, fail(), that I added to your code. You should always check the return values of any function that you call when programming in C. Here it is particularly important to check, first if the terminal supports color with the has_colors() function, and then if the call to start_color() is successful. If either of these fail, the fail() function is called with an error message, and the program exits with the EXIT_FAILURE value. The function has_colors() returns a bool, and the start_color() function returns an int (OK if successful, otherwise ERR).
Now that colors have been initialized, I see that the lower border of your menu selection window is being overwritten by the menu text. To fix this, I changed the size of your window, making it one line taller:
WINDOW * menuwin=newwin(7, dlug-12, szer-9, 6);
The fundamental problem of improper printing that you reported was because of a misplaced brace in the for loop controlling the printing of the menu items. I took the opportunity to reorganize the loop a bit; now there is only one call to mvwprintw(). The A_REVERSE attribute is set before printing if the current item is also the selected item, and it is again unset after printing.
I also changed the limit tests in the switch statement from equalities to inequalites. It is better practice to use , e.g., if (zaznacz < 0) instead of if (zaznacz == -1) in such cases.
I added a newline character to the beginning of the format string in the final printw(), since some of the selections are too long to fit in the window at the end of the title. You can move this output wherever you like.
Finally, I added a refresh() after the final printw() statement, and a getch() to wait for the user to hit ENTER before exiting the program. It is very important to cleanup by calling endwin() before exiting an NCurses program. This function reverses changes made to your terminal by NCurses while your program was running, and failure to do this can lead to terminal unpleasantries.
#include <stdio.h>
#include <ncurses.h>
#include <string.h>
#include <menu.h>
#include <stdlib.h> // added for exit() function
void fail(char *msg) {
endwin();
puts(msg);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
/* Commandline argument currently unused */
(void) argc;
(void) argv;
int i, c;
(void) c; // c is currently unused
char powitanie[]="SLOWNIK UNIWERSALNY";
int szer, dlug; //wartosci dlugosci i szerokosci terminalu
initscr(); //Inizjalizacja całości ncurses, kolory itp
raw();
noecho();
keypad(stdscr, TRUE);
/* Test to see if terminal has colors */
if (has_colors() == false) {
fail("Colors unavailable\n");
}
if (start_color() != OK) {
fail("Unable to start colors\n");
}
//init_pair(1, COLOR_BLUE, COLOR_BLACK); //wybór kolorów
getmaxyx(stdscr, szer, dlug); //pobranie rozmiarów terminalu
move(szer/2, (dlug-strlen(powitanie))/2); //przesuwamy kursor na środek (tak aby się ładnie wydrukowało)
//attron(COLOR_PAIR(1)); //Aktywujemy wybrane kolory
printw(powitanie); //Drukujemy powitanie
//attroff(COLOR_PAIR(1));//Dezaktywujemy kolory
refresh();//Odswiezamy (inaczej się nie wyswietli)
WINDOW * menuwin=newwin(7, dlug-12, szer-9, 6); //Definiujemy i tworzymy 'okno'
box(menuwin, 0, 0);
refresh();//ponownie odświeżamy aby okno się pojawiło
wrefresh(menuwin);//odświeżamy samo okno
keypad(menuwin, TRUE);//umozliwiamy dzialanie klawiatury w oknie
char *opcje[] = {
"Tlumacz z Polskiego na Angielski",
"Tlumacz z Angielskiego na Polski",
"Edystuj slownik",
"Wybierz slownik",
"Wyjdz",
};
int wybor;
int zaznacz=0;
while(1)//cala ta petla sluzy ciaglemu tworzeniu menu z podswietleniem wybranego elementu
{
for(i = 0; i < 5; i++) {
if(i == zaznacz)
wattron(menuwin, A_REVERSE);
mvwprintw(menuwin, i+1, 1, opcje[i]);
if (i == zaznacz)
wattroff(menuwin, A_REVERSE);
}
wybor = wgetch(menuwin);
switch(wybor)
{
case KEY_UP:
zaznacz--;
if(zaznacz < 0) zaznacz = 0;//zabezpieczenie przed wyjsciem "poza" menu
break;
case KEY_DOWN:
zaznacz++;
if(zaznacz > 4) zaznacz = 4;
break;
default:
break;
}
if(wybor==10) break;
}
printw("\nWybrano:%s", opcje[zaznacz]);
refresh();
/* Wait for user to press enter to exit */
getch();
/* Need to cleanup before exit */
endwin();
return 0;
}