I'm making a board like this
GtkWidget *board[x][y];
If I do an array of buttons, how can I know which button was pressed?
Does
g_signal_connect(G_OBJECT(board[][]), "clicked",
G_CALLBACK(board_button_pressed), NULL);
// I want to know what [][] they pressed, how could I verify/check this?
return which button of the array was pressed? Or do I have to make a separate function for each of the board pieces?
For example:
OOO
OXO
OOO
How to know which button was pressed if all of the buttons are named the same?
One of the simplest way would be to just send the information when you are connecting to the callback as data. Something on these lines:
...
typedef struct _identifier{
int x;
int y;
}identifier;
static void button_clicked_cb(GtkButton *button, gpointer data)
{
(void)button; /*To get rid of compiler warning*/
identifier *id = data;
printf("\n id = %d, %d\n", id->x, id->y);
return;
}
....
identifier id[x*y]; /* Size of x*y of the board*/
unsigned int counter = 0;
for (i = 0; i < x; i++)
{
for (j = 0; j < y; j++)
{
id[counter].x = i;
id[counter].y = j;
board[i][j] = gtk_button_new ();
g_signal_connect(board[i][j], "clicked", G_CALLBACK(button_clicked_cb), &id[counter]);
counter++;
}
}
Please note that "clicked" signal is associated only with GtkButton. If you need to use with GtkWidget then look at "button-press-event" or "button-release-event", in which case the callback signature will also change.
Hope this helps!
Related
I am running multiple threads and need to create a copy of the same window across each thread. Each one is display values relevant to what that thread is doing (calculating prime numbers in this case).
#include "stress.h"
//------------------------------
void windowUpdate(int *ptr) {
//------------------------------
GtkLabel *lbl_thread;
GtkLabel *lbl_total;
GtkLabel *lbl_latest;
lbl_thread = GTK_LABEL(gtk_builder_get_object(stressBuilder, "lbl_thread"));
char buffer[512];
sprintf(buffer, "%i", ptr);
gtk_label_set_text(lbl_thread, buffer);
}
//------------------------------
void windowCreate() {
//------------------------------
//This is where the window instance code will eventually live
}
//------------------------------
void prime(int *ptr) {
//------------------------------
int i = 3, count, c;
const int n = INT_MAX;
if ( n >= 1 ) {
printf("First %d prime numbers are :\n",n);
printf("2\n");
}
for ( count = 2 ; count <= n ; ) {
for ( c = 2 ; c <= i - 1 ; c++ ) {
if ( i%c == 0 )
break;
}
if ( c == i ) {
printf("Thread %i: %d\n", ptr, i);
count++;
}
i++;
}
}
//------------------------------
void debugMesg(int *ptr) {
//------------------------------
printf("A thread with ID: %i was created\n", ptr);
windowUpdate(ptr);
prime(ptr);
}
//------------------------------
void genThreads(GtkBuilder *builder, int threads) {
//------------------------------
XInitThreads();
stressBuilder = builder; //points to the builder used in main()
//------------------------------
GtkWidget *winStress;
//------------------------------
winStress = GTK_WIDGET(gtk_builder_get_object(stressBuilder, "win_thread"));
gtk_widget_queue_draw(winStress);
gtk_widget_show(winStress);
int proc[threads];
pthread_t prime[threads];
char* id;
for(int i = 0; i < threads; i++) {
id = (char) i;
proc[i] = pthread_create(&prime[i], NULL, debugMesg, (int *) id);
}
}
genThreads() is the function where the threads are created. It's also temporarily responsible for displaying the win_thread window. the windowUpdate() function needs to be able to alter the values for the instance of the window corresponding to the thread its running on.
I'm fairly new to using threads btw, in case I've made any rookie errors.
The whole program is a bit to long to post here, so here is a link to the repo in case you want to look at main() or stress.h or something.
Thanks everyone :D
I have a big code of GTK2 in which I´m having troubles updating the value of an integer (in this case trigan, that its defined in the main body and callbacked to the two functions that are giving me this problem).
I intend to press the button RUN that calls the function RUN that starts displaying numbers in real time. Then, while text its running I will press STOP button that calls the function STOP, updating the value of trigan to 1.
Here is the piece of code in question:
void STOP(GtkWidget *widget, GObject *context_object_stp)
{
GtkEntry *trigan = g_object_get_data (context_object_stp, "trigan");
trigan=1;
}
void RUN(GtkWidget *widget, GObject *context_object)
{
GtkEntry *buffer= g_object_get_data (context_object, "buffer");
GtkEntry *wins = g_object_get_data (context_object, "wins");
GtkEntry *trigan = g_object_get_data (context_object, "trigan");
GtkWidget iter;
GtkTextIter iterscrll;
GtkTextMark *mark;
mark = gtk_text_buffer_get_insert(buffer);
gtk_text_buffer_get_iter_at_mark(buffer, &iterscrll, mark);
gtk_text_buffer_get_iter_at_offset(buffer, &iter, 0);
trigan=0;
int i=0;
int k=0;
for (i=0; i<90; i=i+1)
{
while (trigan==1)
{
}
gchar * stuff = g_strdup_printf("%d"" [%d]\n", i, trigan);
/* Inserts buffer at position iter. */
gtk_text_buffer_insert(buffer, &iter, stuff, -1);
g_free(stuff);
/* Forcing. */
while (gtk_events_pending())
gtk_main_iteration();
/* Scrolls text_view the minimum distance such that mark is contained within the visible area of the widget. */
gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(wins), mark);
for (k=0; k<50000000; k=k+1)
{
k++;
}
k=0;
}
}
My logic say that whit this value of trigan=1 the
while (trigan==1)
{
}
should "stop" the function RUN, but it doesn't.
Help please!
yes, your assumption is correct but take a look at this extract of your code:
triga=0;
int i=0;
int k=0;
for (i=0; i<90; i=i+1)
{
while (triga==1)
{
}
as you see, triga is defined, assigned to 0 an never manipoulated in between before the while... so the condition while (triga==1) is false...
that is the reason..
I'm working on a project in C using gtk+ 2.0.
I must check if the user has pressed left click on a image. I thought to call a function when left click is pressed and to get the position of the mouse, but how can I do that?
I hope I can assume you know how to connect an event to a widget, but if not: Here's a previous answer of mine that demonstrates how to do just that.
g_signal_connect for right mouse click?
As you can see there the event is passed as a GdkEventButton * (event from now on). This struct has the member fields that you are after: event->x and event->y both are gdouble fields.
Anyway, #unwind is right. As the GTK docs clearly state:
GtkImage is a “no window” widget (has no GdkWindow of its own), so by default does not receive events. If you want to receive events on the image, such as button clicks, place the image inside a GtkEventBox, then connect to the event signals on the event box.
GtkImage is not the only "windowless" widget, BTW. GtkLabel, for example, requires a similar approach if you want to handle clicks on a label. Anyway: More info here.
The man page then continues with a full code example of how to handle clicks on a GtkImage widget. Just look for the title "Handling button press events on a GtkImage." for the full explanation, but here's the code in case the link breaks:
static gboolean
button_press_callback (GtkWidget *event_box,
GdkEventButton *event,
gpointer data)
{
g_print ("Event box clicked at coordinates %f,%f\n",
event->x, event->y);
// Returning TRUE means we handled the event, so the signal
// emission should be stopped (don’t call any further callbacks
// that may be connected). Return FALSE to continue invoking callbacks.
return TRUE;
}
static GtkWidget*
create_image (void)
{
GtkWidget *image;
GtkWidget *event_box;
image = gtk_image_new_from_file ("myfile.png");
event_box = gtk_event_box_new ();
gtk_container_add (GTK_CONTAINER (event_box), image);
g_signal_connect (G_OBJECT (event_box),
"button_press_event",
G_CALLBACK (button_press_callback),
image);
return image;
}
The problem is that the GtkImage widget which is used to show an image in GTK+ does not generate events.
It's a "nowindow" widget, meaning that it's a passive container, which is used to display information and not to interact with the user.
You can fix that by wrapping the image in a GtkEventBox, which will add event support.
In GTK you can use the button-pressed-event gtk widget to do this
In pure c, from Programming Simplified
#include<graphics.h>
#include<conio.h>
#include<stdio.h>
#include<dos.h>
int initmouse();
void showmouseptr();
void hidemouseptr();
void getmousepos(int*,int*,int*);
union REGS i, o;
main()
{
int gd = DETECT, gm, status, button, x, y, tempx, tempy;
char array[50];
initgraph(&gd,&gm,"C:\\TC\\BGI");
settextstyle(DEFAULT_FONT,0,2);
status = initmouse();
if ( status == 0 )
printf("Mouse support not available.\n");
else
{
showmouseptr();
getmousepos(&button,&x,&y);
tempx = x;
tempy = y;
while(!kbhit())
{
getmousepos(&button,&x,&y);
if( x == tempx && y == tempy )
{}
else
{
cleardevice();
sprintf(array,"X = %d, Y = %d",x,y);
outtext(array);
tempx = x;
tempy = y;
}
}
}
getch();
return 0;
}
int initmouse()
{
i.x.ax = 0;
int86(0X33,&i,&o);
return ( o.x.ax );
}
void showmouseptr()
{
i.x.ax = 1;
int86(0X33,&i,&o);
}
void getmousepos(int *button, int *x, int *y)
{
i.x.ax = 3;
int86(0X33,&i,&o);
*button = o.x.bx;
*x = o.x.cx;
*y = o.x.dx;
}
I am trying to make a controller for a game with SDL 2(didn't want to ask on gamedev since it is not a game issue directly) I use SDL_GetKeyboardEvent to see if the navigation arrows are being pressed but it apparently doesn't work, it is supposed to print a value 1 or -1 if one of those keys is pressed but it doesn't it just prints 0 even if I hold the key down for several seconds, it is like it doesn't detect that the key is being pressed. I searched all over the internet and this is how they do it, but it doesn't work for me.
#define SDL_MAIN_HANDLED
#include <stdio.h>
#include "SDL.h"
/* I'll add some code later
so something that isn't used
might be initialized
*/
int main (void)
{
int a = 1;
int x;
int z;
SDL_Event quit;
const Uint8 *keys = SDL_GetKeyboardState(NULL);
SDL_Init(SDL_INIT_VIDEO);
while(a)
{
SDL_PollEvent(&quit);
if(quit.type == SDL_QUIT)
a = 0;
if(keys[SDL_SCANCODE_UP])
z = 1;
else if(keys[SDL_SCANCODE_DOWN])
z = -1;
else
z = 0;
if(keys[SDL_SCANCODE_LEFT])
x = -1;
else if(keys[SDL_SCANCODE_RIGHT])
x = 1;
else
x = 0;
printf("%d, %d\n", x, z);
//This is supposed to print
//x, z values so if up arrow is pressed it will print 0, 1 and if
//down arrow is pressed it will print 0, -1: the same with horizontal ones.
//1 or -1, 1 or -1
}
SDL_Quit();
return 0;
}
Read the documentation: wiki
Note: This function gives you the current state after all events have been processed, so if a key or button has been pressed and released before you process events, then the pressed state will never show up in the SDL_GetKeyboardState() calls
What it means is?
You need to process all events. How? Looping the PollEvent, after the loop (or if you want to check in the loop, check at the end), the SDL_GetKeyboardState is usable.
So, go through the loop, check for keyboards states. Do not forget to always go through the loop before checking for keys
e.g.
while (game)
{
/*! updates the array of keystates */
while ((SDL_PollEvent(&e)) != 0)
{
/*! request quit */
if (e.type == SDL_QUIT)
{
game = false;
}
}
if (keys[SDL_SCANCODE_RIGHT])
std::cout << "Right key";
}
You'll need to create a window with SDL_SetVideoMode to get mouse and keyboard events.
Here is my InputManager update function that updates the user input from the keyboard and mouse. Notice the const_cast needed to be able to update the class variable Uint8* keysArray;. This way, more than one event can be processed at once.
void update() {
SDL_PumpEvents();
// update keyboard state
keysArray = const_cast <Uint8*> (SDL_GetKeyboardState(NULL));
if (keysArray[SDL_SCANCODE_RETURN])
printf("MESSAGE: <RETURN> is pressed...\n");
if (keysArray[SDL_SCANCODE_RIGHT] && keysArray[SDL_SCANCODE_UP])
printf("MESSAGE: Right and Up arrows are pressed...\n");
// update mouse location and button states
SDL_GetMouseState(&x, &y);
getMouseButtonStates();
}
In a MFC dialog, I have used a CListCtrl with checkbox. I want to disable multi checkbox selection , so that user can only select a single checkbox at a time. What is the best way to achieve this.I have done this
void SomeClass::OnClickList(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
int nSelectedItemIndex = -1;
nSelectedItemIndex = m_ListCtrl.GetNextItem(-1, LVNI_SELECTED);
int nCount = m_ListCtrl.GetItemCount();
for(int nItem = 0; nItem < nCount; nItem++)
{
m_ListCtrl.SetCheck(nItem,false);
}
if(nSelectedItemIndex != -1)
m_ListCtrl.SetCheck(nSelectedItemIndex,true);
*pResult = 0;
}
Somehow I think this method is not so proper and can be made better in other way. All suggesions are welcomed.
EDIT: UPDATE: after writing the code , everything is working but I am facing a new problem.
calling SetCheck() function inside OnItemChanged message handler function, it is calling the same function again, creating a recursion.Thus selection change is somehow slow. How to avoid this.Please help. ????
Finally I have solved it . Now the checkbox and selection works at par. selecting checkbox selects the row and vice versa and one selection is possible. the code:
void SomeClass::ResetAllCheckBox()
{
int nCount = m_ListCtrl.GetItemCount();
for(int nItem = 0; nItem < nCount; nItem++)
{
m_ListCtrl.SetCheck(nItem,false);
}
}
//Handler for ON_NOTIFY(NM_CLICK,...)
void SomeClass::OnClickList(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
NMLISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
LVHITTESTINFO hitinfo;
int nPosCB=-1,nPos=-1;
hitinfo.pt = pNMListView->ptAction;
//Make the hit test...
nPosCB = m_ListCtrl.HitTest(&hitinfo);
if(hitinfo.flags != LVHT_ONITEMSTATEICON)
return;
ResetAllCheckBox();
nPos = m_ListCtrl.GetNextItem(-1,LVNI_SELECTED);
m_ListCtrl.SetItemState(nPos, ~LVIS_SELECTED, LVIS_SELECTED);
m_ListCtrl.SetItemState(nPosCB, LVIS_SELECTED, LVIS_SELECTED);
m_ListCtrl.SetSelectionMark(nPosCB);
*pResult = 0;
}
//Handler for ON_NOTIFY(LVN_ITEMCHANGED,...)
void SomeClass::OnItemchangedList(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
int nPos = -1;
ResetAllCheckBox();
nPos = m_ListCtrl.GetNextItem(-1,LVNI_SELECTED);
if(nPos != -1)
m_ListCtrl.SetCheck(nPos);
int nCount = m_ListCtrl.GetItemCount();
int nSelectedItemIndex = -1;
for(int nItem = 0; nItem < nCount; nItem++)
{
if(m_ListCtrl.GetCheck(nItem)== 1)
nSelectedItemIndex = nItem;
}
*pResult = 0;
}
When creating the control make sure this style is used LVS_SINGLESEL.
It is passed in the CreateEx/CreateEx function. Also available from the resource editor (if control is added through it).
I found a shorter solution. The idea is to detect if the user checked a checkbox. If it is the case, unchecked all the other checboxes, otherwise do nothing. Contrary to the answer by #egur, this solution does not check the checkbox upon selection of the row.
static void DisableAllItemsExcept(CListCtrl& ctrl, int indexToKeepChecked)
{
for (int nItem = 0; nItem < ctrl.GetItemCount(); nItem++)
if (nItem != indexToKeepChecked)
ctrl.SetCheck(nItem, FALSE);
}
//in begin message map
//ON_NOTIFY(LVN_ITEMCHANGED, IDC_SC_LIST, &CMyDlg::OnLvnItemchangedScList)
void CMyDlg::OnLvnItemchangedScList(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
//detect if we checked a new element
if ( (pNMLV->uChanged & LVIF_STATE) && (pNMLV->uNewState & 0x2000) && (pNMLV->uOldState & 0x1000) )
DisableAllItemsExcept(m_lcList, pNMLV->iItem);
*pResult = 0;
}
The detection of state change was based on the following article : Get the notification code from Listview Control checkboxes. The values 0x1000 and 0x2000 do not seems to be defined anywhere in the header file, so maybe I'm using an undocumented feature.