wxlistbox Arrays with CASE and SWITCH not working Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
papayrus
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 204
Joined: Tue Jan 25, 2011 4:55 pm
Location: USA

wxlistbox Arrays with CASE and SWITCH not working

Post by papayrus »

Hello I need help I been trying to make a list box like one I made in C# where you select and item in the listbox and then press a button and it does something like launch internet explorer. In my program I just have a button and a wxlistbox on the frame. I want to make a number of items and when each item is selected each one will do something different when the button is clicked. Here is my code so far it does not work. Thanks for any help.

Code: Select all

void ListBoxFrame::OnButton3Click(wxCommandEvent& event)
{

           for (int i = 0; i < ListBox1.IsSelected.Count; i++)
            {
                switch (ListBox1.IsSelected[i].ToString())
                {
                    case "Foobar":
                        wxMessageBox(_T("Listbox item foobar selected"));
                        break;
                    case "Bazquirk":
                        wxMessageBox(_T("Listbox item Bazquirk selected"));
                        break;
                    case "Widgets":
                        wxMessageBox(_T("Listbox item Widgets selected"));
                        break;
                    case "Gadgets":
                        wxMessageBox(_T("Listbox item Gadgets selected"));

                        break;
                }
            }
}
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Post by PB »

Just few remarks.

1. Is your code valid C++, i.e. does it even compile? I didn't know one can use string literals as switch labels. :S Also the code using IsSelected looks odd, IsSelected is a method returning a bool, not a "property".
2. Generally speaking, you are supposed to create any controls on heap, not on stack.
3. I recommend to check out the Controls sample, particularly MyPanel::OnListBox method.
papayrus
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 204
Joined: Tue Jan 25, 2011 4:55 pm
Location: USA

Post by papayrus »

OK I been doing more research on it. I see that it's not really a C++ thing to use strings in this manner. So I broke down code from samples that came with wxdev but I am using code blocks anyway they all break down to this.

Code: Select all

int sel = event.GetInt();
        wxLogMessage(_T("Listbox item %d selected"), sel);
That makes it put out a wxLogMessage that tells what line number I clicked starting with 0. None of the examples show me how to case this. I don't care if it is a string or integer I just want to be able to say launch internet explorer when the item 0 is selected and then open notepad when item 1 is selected and then open a folder when item 3 is selected. I am still stumped on how to case it but at least I understand now how it is working a bit. Please help me put this together I am stressed out about it lol but really I am.
catalin
Moderator
Moderator
Posts: 1618
Joined: Wed Nov 12, 2008 7:23 am
Location: Romania

Post by catalin »

http://www.fredosaurus.com/notes-cpp/st ... witch.html

But I can't help wondering - is this way faster than googl'ing it yourself?
papayrus
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 204
Joined: Tue Jan 25, 2011 4:55 pm
Location: USA

Post by papayrus »

I did google it. I am just becoming more clear at what I am seeing here now. Thank you for that info it's almost good. I have one more error to fix in my code and I am stumped on why I am getting the error. The error tells me that c1 and c2 and c3 and c4 were not declared in this scope. Here is my code based off of what you gave to me. I know that somewhere in here I need to call ListBox1 so the button can tell the list box what to do. Also I need to declare the c1 c2 c3 and c4. Other than that this is great.

Code: Select all

void ListBoxFrame::OnButton3Click(wxCommandEvent& event)
{
    int expr = event.GetInt();
    switch (expr)
    {
    case c1:
            system("start c:\\progra~1\\intern~1\\iexplore.exe http://update.microsoft.com/microsoftupdate");
        break;

    case c2:
            wxMessageBox(_T("Listbox item c2 selected"));
        break;

    case c2:  // multiple values can share same statements
    case c3:
    case c4:
            wxMessageBox(_T("Listbox item multiple selected"));
        break;

    default:
            wxMessageBox(_T("Listbox item selected"));
    }

}
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Post by PB »

papayrus wrote:I did google it. I am just becoming more clear at what I am seeing here now. Thank you for that info it's almost good. I have one more error to fix in my code and I am stumped on why I am getting the error. The error tells me that c1 and c2 and c3 and c4 were not declared in this scope. Here is my code based off of what you gave to me. I know that somewhere in here I need to call ListBox1 so the button can tell the list box what to do. Also I need to declare the c1 c2 c3 and c4. Other than that this is great.
Well, it's just as the compiler says. You have to declare them somewhere ListBoxFrame::OnButton3Click() can see them. Seems that most logical would be to declare them in ListBoxFrame class, if these are a series of consecutive integers, I would use enum. By the way, it might be good idea to use more informative variable names, not c1 or Button3. ;)

Code: Select all

system("start c:\\progra~1\\intern~1\\iexplore.exe http://update.microsoft.com/microsoftupdate"
I think you better use functions like wxLaunchDefaultBrowser, wxLaunchDefaultApplication (if you're using wxWidgets 2.9+) or wxExecute instead of system(), not to mention hardcoding paths is rarely a good thing.
papayrus
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 204
Joined: Tue Jan 25, 2011 4:55 pm
Location: USA

Post by papayrus »

PB wrote:
papayrus wrote:I did google it. I am just becoming more clear at what I am seeing here now. Thank you for that info it's almost good. I have one more error to fix in my code and I am stumped on why I am getting the error. The error tells me that c1 and c2 and c3 and c4 were not declared in this scope. Here is my code based off of what you gave to me. I know that somewhere in here I need to call ListBox1 so the button can tell the list box what to do. Also I need to declare the c1 c2 c3 and c4. Other than that this is great.
Well, it's just as the compiler says. You have to declare them somewhere ListBoxFrame::OnButton3Click() can see them. Seems that most logical would be to declare them in ListBoxFrame class, if these are a series of consecutive integers, I would use enum. By the way, it might be good idea to use more informative variable names, not c1 or Button3. ;)

Code: Select all

system("start c:\\progra~1\\intern~1\\iexplore.exe http://update.microsoft.com/microsoftupdate"
I think you better use functions like wxLaunchDefaultBrowser, wxLaunchDefaultApplication (if you're using wxWidgets 2.9+) or wxExecute instead of system(), not to mention hardcoding paths is rarely a good thing.
I am using wxwidgets 2.8 now. I understand everything you are saying but I can't get how to declare variables. I use the hardcoded path because I am installing flash active x which I need to launch IE not the default browser.
briceandre
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 672
Joined: Tue Aug 31, 2010 6:22 am
Location: Belgium

Post by briceandre »

Not tested, but it should work...

Code: Select all

wxArrayInt selections;
ListBox1.GetSelections(selections);
for (int i = 0; i < selections.GetCount(); i++)
{
   wxString current_str = ListBox1.GetString(selections.Item(i));

   if (current_str == "Foobar")
   {
      wxMessageBox(_T("Listbox item foobar selected"));
   }
   else if (current_str == "...")
      ...
}
Note that I don't know what is wxMessageBox, so I don't know exactly what you manage to do with it...
papayrus
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 204
Joined: Tue Jan 25, 2011 4:55 pm
Location: USA

Post by papayrus »

briceandre wrote:Not tested, but it should work...

Code: Select all

wxArrayInt selections;
ListBox1.GetSelections(selections);
for (int i = 0; i < selections.GetCount(); i++)
{
   wxString current_str = ListBox1.GetString(selections.Item(i));

   if (current_str == "Foobar")
   {
      wxMessageBox(_T("Listbox item foobar selected"));
   }
   else if (current_str == "...")
      ...
}
Note that I don't know what is wxMessageBox, so I don't know exactly what you manage to do with it...

I tried this and I got errors. Request for member Getselections and also Getstrings says they are not in ListBoxFrame this which is of non class type wxListBox. Also ambiquous overload for operator ==. As far as I know wxMessageBox makes a pop up box with a message in it. Here is the code I tried.

Code: Select all

void ListBoxFrame::OnButton5Click(wxCommandEvent& event)
{
    wxArrayInt selections;
    ListBox1.GetSelections(selections);
    for (int i = 0; i < selections.GetCount(); i++)
    {
   wxString current_str = ListBox1.GetString(selections.Item(i));

        if (current_str == "Foobar")
        {
            wxMessageBox(_T("Listbox item foobar selected"));
        }
        else if (current_str == "Bar")
        {
            wxMessageBox(_T("Listbox item bar selected"));
        }
    }
}
papayrus
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 204
Joined: Tue Jan 25, 2011 4:55 pm
Location: USA

Post by papayrus »

I added wxListBoxCtrl* m_pListBox; to under where it says Initialize(ListBoxFrame)

Code: Select all

ListBoxFrame::ListBoxFrame(wxWindow* parent,wxWindowID id)
{

    //(*Initialize(ListBoxFrame)
and made my button like this

Code: Select all

void ListBoxFrame::OnButton5Click(wxCommandEvent& event)
{
    wxArrayInt selections;
    m_pListBox.GetSelections(selections);
    for (int i = 0; i < selections.GetCount(); i++)
    {
   wxString current_str = m_pListBox.GetString(selections.Item(i));

        if (current_str == "Foobar")
        {
            wxMessageBox(_T("Listbox item foobar selected"));
        }
        else if (current_str == "Bar")
        {
            wxMessageBox(_T("Listbox item bar selected"));
        }
    }
}



it's still not working what am I doing wrong?


Sorry had to edit the post I made all the code was not there.
Now I get m_pListBox was not declared in the button and ambiguous overload for operator== in current str == "FooBar"[/code]

Ok I just tried this instead. I added this

Code: Select all

enum wxListBoxCtrl {
    wxListBox* m_pListBox };
under helper functions and there is way less errors. I have 3 errors now
expected '}' before '*' token|
expected initializer before '}' token|
expected declaration before '}' token|
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Post by PB »

you have to declare your m_pListBox in the wxFrameListBox and create it in its constructor like this:

Code: Select all

class ListBoxFrame : public wxFrame
{
   ...
private:
   wxListBox* m_pListBox;
   ...
}

ListBoxFrame::ListBoxFrame(...)
{

  ...
  m_pListBox = new wxListBox(this, ...
}
The enum was meant to be for numeric case labels for the switch statement. If you go by comparing strings, it's not needed.
As for string comparison, if for some reason simple comparison using == doesn't work for you just use appropriate wxString comparison function.

Anyway, I really recommend to learn C++, you won't get anywhere like this - you're struggling with the language here, not wxWidgets. If you've mastered C#, you should be able to grasp the basics of C++ easily and then build on them fast. If you don't want to learn it, just create the application in the language and framework you're comfortable with.
papayrus
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 204
Joined: Tue Jan 25, 2011 4:55 pm
Location: USA

Post by papayrus »

PB wrote:you have to declare your m_pListBox in the wxFrameListBox and create it in its constructor like this:

Code: Select all

class ListBoxFrame : public wxFrame
{
   ...
private:
   wxListBox* m_pListBox;
   ...
}

ListBoxFrame::ListBoxFrame(...)
{

  ...
  m_pListBox = new wxListBox(this, ...
}
The enum was meant to be for numeric case labels for the switch statement. If you go by comparing strings, it's not needed.
As for string comparison, if for some reason simple comparison using == doesn't work for you just use appropriate wxString comparison function.

Anyway, I really recommend to learn C++, you won't get anywhere like this - you're struggling with the language here, not wxWidgets. If you've mastered C#, you should be able to grasp the basics of C++ easily and then build on them fast. If you don't want to learn it, just create the application in the language and framework you're comfortable with.
I am trying to learn it I really am I need some idea of structure on this to move on. I will try what you just showed me. It's definitly different in some ways than c# I want to know C++ as well. If I can make this listbox I can then look at it and figure out what goes where and why and it will help me with other controls as well.
papayrus
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 204
Joined: Tue Jan 25, 2011 4:55 pm
Location: USA

Post by papayrus »

papayrus wrote:
PB wrote:you have to declare your m_pListBox in the wxFrameListBox and create it in its constructor like this:

Code: Select all

class ListBoxFrame : public wxFrame
{
   ...
private:
   wxListBox* m_pListBox;
   ...
}

ListBoxFrame::ListBoxFrame(...)
{

  ...
  m_pListBox = new wxListBox(this, ...
}
The enum was meant to be for numeric case labels for the switch statement. If you go by comparing strings, it's not needed.
As for string comparison, if for some reason simple comparison using == doesn't work for you just use appropriate wxString comparison function.

Anyway, I really recommend to learn C++, you won't get anywhere like this - you're struggling with the language here, not wxWidgets. If you've mastered C#, you should be able to grasp the basics of C++ easily and then build on them fast. If you don't want to learn it, just create the application in the language and framework you're comfortable with.
I am trying to learn it I really am I need some idea of structure on this to move on. I will try what you just showed me. It's definitly different in some ways than c# I want to know C++ as well. If I can make this listbox I can then look at it and figure out what goes where and why and it will help me with other controls as well.
OK I think I got it maybe but where and how can I declare the cases? C1, C2, C3. etc?
Here let me show you what I did first.
In the file ListBoxMain.h I added

Code: Select all

wxListBox* m_pListBox;
under where it says private. Then in the file ListBoxMain.cpp I made this into this.

Code: Select all

ListBoxFrame::~ListBoxFrame()
{
    m_pListBox = new wxListBox(this, ID_LISTBOX1, wxPoint(24,32), wxSize(328,144), 0, 0, 0, wxDefaultValidator, _T("ID_LISTBOX1"));
    m_pListBox->Append(_("Ran"));
    m_pListBox->Append(_("Loast"));
    m_pListBox->Append(_("Fou d"));


    //(*Destroy(ListBoxFrame)
    //*)
}
now I just need to declare the cases c1, c2, c3 etc
Also I just noticed that my appended text does not show up. If I comment out the code area that says I need to declare c1 c2 and c3 it runs fine but no appended text there.
Can someone send me an example of a frame with a listbox on it with some items add one button to the frame and then make it so when i highlight the first item and press the button it opens notepad and then when I highlight and press the button on the second item it opens IE and when I highlight and press the third button it makes a messagebox please? Or what else can I do here to declare the cases of c1 c2 and c3?
papayrus
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 204
Joined: Tue Jan 25, 2011 4:55 pm
Location: USA

Post by papayrus »

Well I made it work. I don;t know if this is correct but it works. I changed the c1 c2 c3 in case to numbers 1 ,2 ,3 etc and it works. Here is the final code.

Code: Select all

void ListBoxFrame::OnListBox1Select(wxCommandEvent& event)
{
    int expr = event.GetInt();
    switch (expr)
    {
    case 0:
            system("start c:\\progra~1\\intern~1\\iexplore.exe http://update.microsoft.com/microsoftupdate");
        break;

    case 1:
            wxMessageBox(_T("Listbox item 2 selected"));
        break;

    case 2:
            wxMessageBox(_T("Listbox item 3 selected"));
        break;

    case 3:
            wxMessageBox(_T("Listbox item 4 selected"));
        break;

    }
}
Just add that code to the wxListBox or a button and you don't need to declare this and that. Thanks for the help guys.

NOTE it is not working properly when added to a button it just keeps launching the first case It is working properly when added to the OnListBox1Select directly.
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Post by PB »

Have you checked out the Controls sample and wxListBox documentation as I advised you earlier? It would really save you a lot of time.
You should do something like this for starters, a real application should have much more, e.g. enable/disable a button if there's an item selected or not, doubleclick on an item acting as if default button was pressed etc.

Code: Select all

class ListBoxFrame : public wxFrame {
...
private:
...
   enum ListBoxIndices {
     LBI_RUN_NOTEPAD = 0,
     LBI_RUN_IE,
     LBI_SHOW_MSGBOX
   };
   wxListBox* m_pListBox;
...
};

ListBoxFrame::ListBoxFrame(...

...
   m_pListBox = new ...
   
   wxCHECK(m_pListBox->Append(_("Launch Notepad")) == LBI_RUN_NOTEPAD);
   wxCHECK(m_pListBox->Append(_("Launch Internet Explorer")) == LBI_RUN_IE);
   wxCHECK(m_pListBox->Append(_("Show a MessageBox")) == LBI_SHOW_MSGBOX);
...
}

void ListBoxFrame::OnButtonClick(wxCommandEvent& event)
{
    int idx = m_pListBox->GetSelection();
    if (idx == wxNOT_FOUND)
       return; // there's no item selected
    switch (idx) {
       case LBI_RUN_NOTEPAD:
           wxExecute("notepad.exe");  // just a dummy 
           break;
       case LBI_RUN_IE:
           wxExecute("iexplore.exe"); // just a dummy 
           break;
       case LBI_SHOW_MSGBOX:
           wxMessageBox( ...
           break;
       default:
           wxFAIL_MSG("Invalid index in ListBoxFrame::OnButtonClick"); 
    }
}
I have to admit that I always used user data in situations like this, never relied on string values (which can be localized) or list indices when I dealt with list controls.
Post Reply