Related
I have enabled keypad for my_win and yet when I press KEY_UP after running the program, nothing happens. The stranger thing is that it works completely fine with stdscr. It appears to only be an issue with my_win.
/* Selects different elements of the list */
while ((ch = wgetch(my_win)) != 'q')
{
sprintf(item, "%-12s", list[i]);
mvwprintw(my_win, i + 1, 2, "%s", item);
switch(ch)
{
case KEY_LEFT:
destroy_win(my_win);
my_win = create_newwin(height, width, starty,--startx);
wprintw(my_win, "This is some text");
wrefresh(my_win);
break;
case 'd':
destroy_win(my_win);
my_win = create_newwin(height, width, starty,++startx);
wprintw(my_win, "This is some text");
wrefresh(my_win);
break;
case 'w':
destroy_win(my_win);
my_win = create_newwin(height, width, --starty,startx);
wprintw(my_win, "This is some text");
wrefresh(my_win);
break;
case 's':
destroy_win(my_win);
my_win = create_newwin(height, width, ++starty,startx);
wprintw(my_win, "This is some text");
wrefresh(my_win);
break;
case KEY_UP:
i--;
i = (i < 0) ? 4 : i;
break;
case KEY_DOWN:
i++;
i = (i < 0) ? 4 : i;
break;
}
The keypad function applies only to the window given as its parameter. When you use newwin, etc., those return a window where the keypad mode is not set.
The newwin documentation points out
Regardless of the function used for creating a new window (e.g.,
newwin, subwin, derwin, newpad), rather than a duplicate (with dupwin),
all of the window modes are initialized to the default values. These
functions set window modes after a window is created:
idcok, idlok, immedok, keypad, leaveok, nodelay, scrollok,
setscrreg, syncok, wbkgdset, wbkgrndset, and wtimeout
I compiled this simple ncurses program and the up down keys are unresponsive.
Any idea why this does not work?
I am using Fedora Linux 5.7.16-200.fc32.x86_64 the default terminal emulator is XTerm(351). I got no errors or warning building ncurses or making the app.
cc -o test test.c -lncurses
/* test.c */
#include <stdlib.h>
#include <stdio.h>
#include <curses.h>
int main(void) {
WINDOW * mainwin, * childwin;
int ch;
/* Set the dimensions and initial
position for our child window */
int width = 23, height = 7;
int rows = 25, cols = 80;
int x = (cols - width) / 2;
int y = (rows - height) / 2;
/* Initialize ncurses */
if ( (mainwin = initscr()) == NULL ) {
fprintf(stderr, "Error initialising ncurses.\n");
exit(EXIT_FAILURE);
}
/* Switch of echoing and enable keypad (for arrow keys) */
noecho();
keypad(mainwin, TRUE);
/* Make our child window, and add
a border and some text to it. */
childwin = subwin(mainwin, height, width, y, x);
box(childwin, 0, 0);
mvwaddstr(childwin, 1, 4, "Move the window");
mvwaddstr(childwin, 2, 2, "with the arrow keys");
mvwaddstr(childwin, 3, 6, "or HOME/END");
mvwaddstr(childwin, 5, 3, "Press 'q' to quit");
refresh();
/* Loop until user hits 'q' to quit */
while ( (ch = getch()) != 'q' ) {
switch ( ch ) {
case KEY_UP:
if ( y > 0 )
--y;
break;
case KEY_DOWN:
if ( y < (rows - height) )
++y;
break;
case KEY_LEFT:
if ( x > 0 )
--x;
break;
case KEY_RIGHT:
if ( x < (cols - width) )
++x;
break;
case KEY_HOME:
x = 0;
y = 0;
break;
case KEY_END:
x = (cols - width);
y = (rows - height);
break;
}
mvwin(childwin, y, x);
}
/* Clean up after ourselves */
delwin(childwin);
delwin(mainwin);
endwin();
refresh();
return EXIT_SUCCESS;
}
The example doesn't repaint the child-window (so nothing seems to happen), and doesn't use cbreak (so nothing happens until you press Return (i.e., newline).
I did this change to see what it does:
> diff -u foo.c.orig foo.c
--- foo.c.orig 2020-08-30 06:00:47.000000000 -0400
+++ foo.c 2020-08-30 06:02:50.583242935 -0400
## -29,6 +29,7 ##
/* Switch of echoing and enable keypad (for arrow keys) */
+ cbreak();
noecho();
keypad(mainwin, TRUE);
## -85,6 +86,7 ##
}
mvwin(childwin, y, x);
+ wrefresh(childwin);
}
Some terminal descriptions may use the same character ControlJ for cursor-down (and get mapped into KEY_ENTER rather than KEY_DOWN—see source code). After allowing for the other two problems, you may be seeing that.
How can I load the ncurses set_field_buffer with a two-byte UTF-8 character?
Some context. I am attempting to build an ncurses form to capture latitude and longitude numbers in degrees, minutes and seconds. In the spirit of standing on the shoulders of the giants, I have adapted this code: https://gist.github.com/alan-mushi/c8a6f34d1df18574f643. I have also:
Added #include <locale.h> to the code.
Added setlocale(LC_ALL, ""); to the code.
Linked to ncurses, not ncursesw.
The following picture shows how the form turned out.
enter image description here
That letter M after the 137 is the problem. It has to be the degrees sign (°).
I loaded all of the characters shown on the form using set_field_buffer. My code for that is:
set_field_buffer(fields[0], 0, "Site A:");
set_field_buffer(fields[1], 0, "w"); /* Station: n, s, w or e. */
set_field_buffer(fields[2], 0, "137"); /* Degrees */
set_field_buffer(fields[3], 0, "\u00B0"); /* Degrees symbol*/
set_field_buffer(fields[4], 0, "22"); /* Minutes */
set_field_buffer(fields[5], 0, "'"); /* Minutes symbol*/
set_field_buffer(fields[6], 0, "45.92"); /* Seconds */
set_field_buffer(fields[7], 0, "\u0022"); /* Seconds symbol*/
Although field 3 is set for "\u00B0", the letter M shows. Alan Mushi's code allows you to press F2 to see the contents of the buffers. The "\u00B0" is rendered as M-B. That suggests to me that set_field_buffer accepts two-byte UTF-8 characters but does not render them correctly. I cannot find a specification detailing what is allowed.
The call to setlocale has to be before the initscr call. Otherwise, ncurses will not use that information, and you will see the data presented that way:
If the locale is not initialized, the library assumes that characters
are printable as in ISO-8859-1, to work with certain legacy programs.
You should initialize the locale and not rely on specific details of
the library when the locale has not been setup.
The bytes used for \u00b0 are \302 and \260 (octal). If you link with ncurses rather than ncursesw, you will of course see an odd display, since the (narrow) ncurses library knows nothing about UTF-8. It relies upon the <ctype.h> macros such as isprint to tell it whether a character is printable in the current locale. For GNU libc (and some others), those macros return false for all of the codes from \177 to \377, making ncurses display those as a printable form described in the keyname manpage.
Printable characters are displayed as themselves, e.g., a one-character string containing the key.
Control characters are displayed in the ^X notation.
DEL (character 127) is displayed as ^?.
Values above 128 are either meta characters (if the screen has not
been initialized, or if meta(3x) has been called with a TRUE parameter), shown in the M-X notation, or are displayed as themselves.
In the latter case, the values may not be printable; this follows
the X/Open specification.
Though not emphasized in the manual page, unctrl and keyname give the same result for those characters.
The addch manpage alludes to this (mentioning ^X because it is the most often encountered):
If ch is any other control character, it is drawn in ^X notation.
Calling winch after adding a control character does not return the
character itself, but instead returns the ^-representation of the control character.
Now, using ncursesw (because the manual page indicates this is required for a locale using "wide characters" such as Unicode):
--- fields_magic.c.orig 2020-07-08 17:49:58.000000000 -0400
+++ fields_magic.c 2020-07-08 17:58:01.650425188 -0400
## -4,15 +4,16 ##
* How to run:
* gcc -Wall -Werror -g -pedantic -o test fields_magic.c -lform -lncurses
*/
-#include <ncurses/ncurses.h>
-#include <ncurses/form.h>
+#include <curses.h>
+#include <form.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
+#include <locale.h>
static FORM *form;
-static FIELD *fields[5];
+static FIELD *fields[15];
static WINDOW *win_body, *win_form;
/*
## -55,7 +56,7 ##
for (i = 0; fields[i]; i++) {
printw("%s", trim_whitespaces(field_buffer(fields[i], 0)));
- if (field_opts(fields[i]) & O_ACTIVE)
+ if (field_opts(fields[i]) & (int) O_ACTIVE)
printw("\"\t");
else
printw(": \"");
## -102,10 +103,11 ##
wrefresh(win_form);
}
-int main()
+int main(void)
{
int ch;
+ setlocale(LC_ALL, "");
initscr();
noecho();
cbreak();
## -126,10 +128,13 ##
fields[4] = NULL;
assert(fields[0] != NULL && fields[1] != NULL && fields[2] != NULL && fields[3] != NULL);
- set_field_buffer(fields[0], 0, "label1");
- set_field_buffer(fields[1], 0, "val1");
- set_field_buffer(fields[2], 0, "label2");
- set_field_buffer(fields[3], 0, "val2");
+ set_field_buffer(fields[0], 0, "w"); /* Station: n, s, w or e. */
+ set_field_buffer(fields[1], 0, "137"); /* Degrees */
+ set_field_buffer(fields[2], 0, "\u00B0"); /* Degrees symbol*/
+ set_field_buffer(fields[3], 0, "22"); /* Minutes */
+ set_field_buffer(fields[4], 0, "'"); /* Minutes symbol*/
+ set_field_buffer(fields[5], 0, "45.92"); /* Seconds */
+ set_field_buffer(fields[6], 0, "\""); /* Seconds symbol*/
set_field_opts(fields[0], O_VISIBLE | O_PUBLIC | O_AUTOSKIP);
set_field_opts(fields[1], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE);
That "\u0022" is not a valid character string (the compiler can tell you that).
Thank you for your comment. In fact the call to setlocale(LC_ALL, "") is before initscr() and the locale on my Debian Bullseye installation is set to UTF-8. I compile the code linked to ncurses and form.
As a sanity check, I'd be grateful if you would run my code and verify that the \u00B0 character does not render correctly.
My code follows:
#include <ncurses.h>
#include <form.h>
#include <cassert> // Was assert.h See https://stackoverflow.com/questions/60127743/changes-not-showing-in-field-in-ncurses
#include <cstdlib> // Was stdlib.h
#include <string.h>
#include <ctype.h>
#include <locale.h>
static FORM *form;
static FIELD *fields[11];
static WINDOW *win_body, *win_form;
/*
* This is useful because ncurses fill fields blanks with spaces.
*/
static char* trim_whitespaces(char *str) {
char *end;
// trim leading space
while(isspace(*str))
str++;
if(*str == 0) // all spaces?
return str;
// trim trailing space
end = str + strnlen(str, 128) - 1;
while(end > str && isspace(*end))
end--;
// write new null terminator
*(end+1) = '\0';
return str;
}
static void driver(int ch) {
int i;
switch (ch) {
case KEY_F(2):
// Or the current field buffer won't be sync with what is displayed
form_driver(form, REQ_NEXT_FIELD);
form_driver(form, REQ_PREV_FIELD);
move(LINES-3, 2);
for (i = 0; fields[i]; i++) {
printw("%s", trim_whitespaces(field_buffer(fields[i], 0)));
if (field_opts(fields[i]) & O_ACTIVE)
printw("\"\t");
else
printw(": \"");
}
refresh();
pos_form_cursor(form);
break;
case KEY_DOWN:
form_driver(form, REQ_NEXT_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_UP:
form_driver(form, REQ_PREV_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_LEFT:
form_driver(form, REQ_PREV_CHAR);
break;
case KEY_RIGHT:
form_driver(form, REQ_NEXT_CHAR);
break;
// Delete the char before cursor
case KEY_BACKSPACE:
case 127:
form_driver(form, REQ_DEL_PREV);
break;
// Delete the char under the cursor
case KEY_DC:
form_driver(form, REQ_DEL_CHAR);
break;
default:
form_driver(form, ch);
break;
}
wrefresh(win_form);
}
int main() {
int ch;
setlocale(LC_ALL, "");
initscr();
noecho();
cbreak();
keypad(stdscr, TRUE);
win_body = newwin(24, 80, 0, 0);
assert(win_body != NULL);
box(win_body, 0, 0);
win_form = derwin(win_body, 20, 78, 3, 1);
assert(win_form != NULL);
box(win_form, 0, 0);
mvwprintw(win_body, 1, 2, "Press F1 to quit and F2 to print fields content");
fields[0] = new_field(1, 7, 0, 0, 0, 0); // Site A:
fields[1] = new_field(1, 1, 0, 9, 0, 0); // Station: n, s, w or e.
fields[2] = new_field(1, 3, 0, 12,0, 0); // Degrees
fields[3] = new_field(1, 1, 0, 15,0, 0); // Degrees symbol
fields[4] = new_field(1, 2, 0, 17,0, 0); // Minutes
fields[5] = new_field(1, 1, 0, 19,0, 0); // Minutes symbol
fields[6] = new_field(1, 5, 0, 21,0, 0); // Seconds
fields[7] = new_field(1, 1, 0, 26,0, 0); // Seconds symbol
fields[8] = new_field(1, 10, 2, 0, 0, 0);
fields[9] = new_field(1, 40, 2, 15, 0, 0);
fields[10] = NULL;
assert(fields[0] != NULL && fields[1] != NULL && fields[2] != NULL && fields[3] != NULL && fields[4] != NULL && fields[5] != NULL && fields[6] != NULL && fields[7] != NULL && fields[8] != NULL && fields[9] != NULL);
set_field_buffer(fields[0], 0, "Site A:");
set_field_buffer(fields[1], 0, "w"); // Station: n, s, w or e.
set_field_buffer(fields[2], 0, "137"); // Degrees
set_field_buffer(fields[3], 0, "\u00B0"); // Degrees symbol
set_field_buffer(fields[4], 0, "22"); // Minutes
set_field_buffer(fields[5], 0, "'"); // Minutes symbol
set_field_buffer(fields[6], 0, "45.92"); // Seconds
set_field_buffer(fields[7], 0, "\u0022"); // Seconds symbol
set_field_buffer(fields[8], 0, "Site B:");
set_field_buffer(fields[9], 0, "");
set_field_opts(fields[0], O_VISIBLE | O_PUBLIC | O_AUTOSKIP);
set_field_opts(fields[1], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE | O_BLANK | O_STATIC); // Station: n, s, w or e.
set_field_opts(fields[2], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE | O_BLANK | O_STATIC); // Degrees
set_field_opts(fields[3], O_VISIBLE | O_PUBLIC | O_AUTOSKIP); // Degrees symbol
set_field_opts(fields[4], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE | O_BLANK | O_STATIC); // Minutes
set_field_opts(fields[5], O_VISIBLE | O_PUBLIC | O_AUTOSKIP); // Minutes symbol
set_field_opts(fields[6], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE | O_BLANK | O_STATIC); // Seconds
set_field_opts(fields[7], O_VISIBLE | O_PUBLIC | O_AUTOSKIP); // Seconds symbol
set_field_opts(fields[8], O_VISIBLE | O_PUBLIC | O_AUTOSKIP);
set_field_opts(fields[9], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE);
set_field_back(fields[1], A_UNDERLINE); // Station: n, s, w or e.
set_field_back(fields[2], A_UNDERLINE); // Degrees
set_field_back(fields[4], A_UNDERLINE); // Minutes
set_field_back(fields[6], A_UNDERLINE); // Seconds
set_field_back(fields[9], A_UNDERLINE);
form = new_form(fields);
assert(form != NULL);
set_form_win(form, win_form);
set_form_sub(form, derwin(win_form, 18, 76, 1, 1));
post_form(form);
refresh();
wrefresh(win_body);
wrefresh(win_form);
while ((ch = getch()) != KEY_F(1))
driver(ch);
unpost_form(form);
free_form(form);
free_field(fields[0]);
free_field(fields[1]);
free_field(fields[2]);
free_field(fields[3]);
free_field(fields[4]);
free_field(fields[5]);
free_field(fields[6]);
free_field(fields[7]);
free_field(fields[8]);
free_field(fields[9]);
free_field(fields[10]);
delwin(win_form);
delwin(win_body);
endwin();
return 0;
}
To begin with I am using the Chili Framework for lessons 1-15 as downloadable here:
http://www.planetchili.net/
I am using DirectX 9 on an old laptop running Windows XP SP3. I have set the Direct3D rendering to software in order to run the framework. I am using Visual Studio Express C++ 2010 with the first service pack installed.
This is the code I am having trouble with:
// Start moving reticle code
DrawReticle(itemLocX, itemLocY, 255, 255, 255);
if(itemLocX == pointA && itemLocX != pointAb)
{
itemLocX += 2;
}
else if(itemLocX == pointBc && itemLocX != pointDa)
{
itemLocX -= 2;
}
if(itemLocY == pointAb && itemLocY != pointBc)
{
itemLocY += 2;
}
else if(itemLocY == pointDa && itemLocX != pointA)
{
itemLocY -= 2;
}
// End moving reticle code
Now Chili's solution is to move along the y axis while checking for x, and x while checking for y. I may post that later, don't have it readily available. You can see it at the beginning of this video:
http://youtu.be/JEmwkQsi8l0
However I wanted to do this logically, as if I was walking the border along an invisible wall inside a box. I wanted it to make sense what was going on. But the cursor won't move, and I see no reason why it doesn't. Here is my game.h:
#pragma once
#include "D3DGraphics.h"
#include "Keyboard.h"
class Game
{
public:
Game( HWND hWnd,const KeyboardServer& kServer );
void Go();
private:
void ComposeFrame();
/********************************/
/* User Functions */
void DrawReticle(int xP, int yP, int cR, int cG, int cB);
/*
xP = x position,
yP = y position,
cR = color red,
cG = color green,
cB = color blue
*/
// TODO: User functions go here
/********************************/
private:
D3DGraphics gfx;
KeyboardClient kbd;
/********************************/
/* User Variables */
int pointA; // Starting at pointA (100, 100) - the top left
int pointAb; // Move from pointA to pointAb (700, 100) - the top right
int pointBc; // Move from pointAb to pointBc (700, 500) - the bottom right
int pointCd; // Move from pointBc to pointCd (100,500) - the bottom left
int pointDa; // Move from pointCd to pointDa (100,100) - the top left
/*
These points describe the process of starting, then four movements. The four points are A, B, C, D. We start at A, then go to B (pointAb, read as A to b), then go to C (pointBc, read as B to c), then go to D (pointCd, read as C to d) then go to A (pointDa, read as D to a).
This can be very confusing, because there are five varibles used. But if we drew it out there would only four points, as well as only four movements. The best way to think of it is that starting is itself a movement, and as you need a place to start from, it itself must have a point. Since you start at A, but haven't yet gone anywhere, pointA is our starting point. Once you start moving, you go from pointA to pointB. Now if we used pointB as our variable it would be confusing,because we would have to move from pointA to pointB to pointC to pointD and then back to pointA. Still five variables, one is repeating, but the first pointA describes where you start, and the last where you end. Since these are two different actions on the same point, I have elected to use two letter names for each of the points you move to, while the point you start at has a single letter name. It was the best way I could clearly think about this process.
*/
int itemLocX; // Initial position of item on the x axis
int itemLocY; // Initial position of item on the y axis
int reticleX; // Initial position of reticle on the x axis
int reticleY; // Initial position of reticle on the y axis
// TODO: User variables go here
/********************************/
};
Here is my game.cpp:
#include "Game.h"
Game::Game( HWND hWnd,const KeyboardServer& kServer )
: gfx(hWnd),
kbd(kServer),
itemLocX(100), // Initial position of item on the x axis
itemLocY(100), // Initial position of item on the y axis
reticleX(400), // Initial position of reticle on the x axis
reticleY(300), // Initial position of reticle on the y axis
pointA(100), // Movement from 0 to A, stopping at A
pointAb(700), // Movement from A to b, stopping at B
pointBc(500), // Movement from B to c, stopping at C
pointCd(700), // Movement from C to d, stopping at D
pointDa(500) // Movement from D to a, stopping at A
{}
void Game::Go()
{
gfx.BeginFrame();
ComposeFrame();
gfx.EndFrame();
}
void Game::DrawReticle(int xP, int yP, int cR, int cG, int cB)
/*
xP = x position,
yP = y position,
cR = color red,
cG = color green,
cB = color blue
*/
{
gfx.PutPixel(xP-5,yP,cR,cG,cB);
gfx.PutPixel(xP-4,yP,cR,cG,cB);
gfx.PutPixel(xP-3,yP,cR,cG,cB);
gfx.PutPixel(xP+3,yP,cR,cG,cB);
gfx.PutPixel(xP+4,yP,cR,cG,cB);
gfx.PutPixel(xP+5,yP,cR,cG,cB);
gfx.PutPixel(xP,yP,cR,cG,cB);
gfx.PutPixel(xP,yP-5,cR,cG,cB);
gfx.PutPixel(xP,yP-4,cR,cG,cB);
gfx.PutPixel(xP,yP-3,cR,cG,cB);
gfx.PutPixel(xP,yP+3,cR,cG,cB);
gfx.PutPixel(xP,yP+4,cR,cG,cB);
gfx.PutPixel(xP,yP+5,cR,cG,cB);
}
void Game::ComposeFrame()
{
// Start draw reticle code
DrawReticle(reticleX, reticleY, 100, 155, 255);
// End draw reticle code
// Start color change code
int yT = 200; // Border 200 pixels from top
int yB = 400; // Border 200 pixels from bottom
int xL = 300; // Border 200 pixels from left
int xR = 500; // Border 200 pixels from right
if(reticleX < xL || reticleX > xR) // Defining color change area for X
{
DrawReticle(reticleX, reticleY, 255, 255, 255);
}
if(reticleY < yT || reticleY > yB) // Defining color change area for Y
{
DrawReticle(reticleX, reticleY, 255, 255, 255);
}
// End color change code
// Start moving reticle code
DrawReticle(itemLocX, itemLocY, 255, 255, 255);
if(itemLocX == pointA && itemLocX != pointAb)
{
itemLocX += 2;
}
else if(itemLocX == pointBc && itemLocX != pointDa)
{
itemLocX -= 2;
}
if(itemLocY == pointAb && itemLocY != pointBc)
{
itemLocY += 2;
}
else if(itemLocY == pointDa && itemLocX != pointA)
{
itemLocY -= 2;
}
// End moving reticle code
// Start border code
if(reticleX < 6)
{
reticleX = 6;
}
else if(reticleX > 794)
{
reticleX = 794;
}
if(reticleY < 6)
{
reticleY = 6;
}
else if(reticleY > 594)
{
reticleY = 594;
}
// End border code
// Start speed change code
int cSpeed = 4; // Default cursor speed
if(kbd.EnterIsPressed()) // Change to high speed
{
cSpeed = 8;
}
if(kbd.SpaceIsPressed()) // Change to low speed
{
cSpeed = 1;
}
if(kbd.RightIsPressed())
{
reticleX += cSpeed;
}
if(kbd.LeftIsPressed())
{
reticleX -= cSpeed;
}
if(kbd.UpIsPressed())
{
reticleY -= cSpeed;
}
if(kbd.DownIsPressed())
{
reticleY += cSpeed;
}
// End speed change code
}
Now I should note here that this should be done without functions and only the basic C++ operators. That's as far as Chili has taught to this point. This is my second attempt to solve this myself, after hours thinking about it and working on it on paper. I'm stuck. Just not seeing it. I think there is a logic error here on my part. I want to understand where my thinking may be mistaken, but more than that, how to think correctly, like the computer, about this.
I am also open to advice regarding my coding style. If I am not being clear enough, or am doing something that should not become a bad habit - basically if there is something I should be doing differently in writing my code I would like to know about it.
Thank you for your help - it is very much appreciated!
I see how you have tried to do this. Personally you have over complexed it.
1: you don't need the != operator in your if statements.
2: try this:
if(itemLocX < 700)
{
itemLocX += 2;
}
3: This worked fine during testing. Another point is that the if statements could be in the wrong order. I changed it to the order in which it moved across the screen in. I have X Y X Y and you have X X Y Y. (unconfirmed) It executes the if statements in order. I have hard coded the answer. set them to variables if you really want to. Hope this helped!
I'm trying to display circles at a user accepted input (usually centers), using OpenCV 2.4.3 (VS 2010). On output image (displayed using 'namedWindow') circle seems to shift column-wise as one marks points along columns. Not sure how I should correct this.
Code:
struct OPTIONS{
OPTIONS(): X(-1), Y(-1), drawing_dot(false){}
int X;
int Y;
bool drawing_dot;
};
OPTIONS options;
void my_mouse_callback( int event, int x, int y, int flags, void* param ){
IplImage* image = (IplImage*) param;
switch( event ){
case CV_EVENT_LBUTTONDOWN:
options.X = x;
options.Y = y;
options.drawing_dot = true;
break;
default:
break;
}
}
int main( void ){
IplImage* image = cvLoadImage("Images/TestRealData/img1.bmp");
Mat frame = imread("Images/TestRealData/img1.bmp");
namedWindow("Test", CV_WINDOW_KEEPRATIO);
cvSetMouseCallback("Test", my_mouse_callback, (void*) image);
while( cvWaitKey(15) != 27 ){
if( options.drawing_dot ){
circle(frame, Point(options.X,options.Y), 3, CV_RGB(0,0,255), 2);
options.drawing_dot = false;
}
imshow("Test", frame);
waitKey(10);
}
cvReleaseImage(&image);
return 0;
}
I think the circle does not shift. The mouse cursor may trick our eyes. You may simply check it by increasing the radius and reduce the thickness of the circle outline like:
circle(frame, Point(options.X, options.Y/2), 15, CV_RGB(0, 0, 255), 1);
By the way, I think if you want to draw the circle at the point you click on, options.Y should not be divided by 2.
Found answer after much time lost - Make sure to specify flags in 'namedWindow'. Changing flag to CV_WINDOW_KEEPRATIO did the trick for me. Hope this helps somebody out there.