WxWidgets - Changing texbox from a file other than the main one

When I click the "Go" button I want the button event in "wxQuestionMain.cpp" to call "somefunction()" which is inside "otherFile.cpp". That works just fine. But I then want to change the text in the textbox "txtCtrl1" from inside "somefunction()" and that won't work because "somefunction()" is not part of the wxWidget class, and I don't want it to be. The wxwidget class is created in "wxQuestionMain.h".

wxQuestionMain.h -> Just creates the class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
	#ifndef WXQUESTIONMAIN_H
	#define WXQUESTIONMAIN_H
	#define BOOST_FILESYSTEM_VERSION 2

	#ifndef WX_PRECOMP
	    #include <wx/wx.h>
	#endif

	#include "wxQuestionApp.h"


	#include <wx/button.h>
	#include <wx/statline.h>
	class wxQuestionDialog: public wxDialog
	{
	    public:
		wxQuestionDialog(wxDialog *dlg, const wxString& title);
		~wxQuestionDialog();

	    protected:
		enum
		{
		    idBtnGo = 1000
		};
		wxStaticText* m_staticText1;
		wxStaticLine* m_staticline1;
		wxButton* BtnGo;
		wxTextCtrl* textCtrl1;

	    private:
		void OnClose(wxCloseEvent& event);
		void OnGo(wxCommandEvent& event);
		DECLARE_EVENT_TABLE()
	};

	void somefunction();

	#endif // WXQUESTIONMAIN_H 


wxQuestionMain.cpp -> Lots of yadda yadda and then at the very bottom the function that handles the buttonclick event.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
	#ifdef WX_PRECOMP
	#include "wx_pch.h"
	#endif

	#ifdef __BORLANDC__
	#pragma hdrstop
	#endif //__BORLANDC__

	#include "wxQuestionMain.h"

	//helper functions
	enum wxbuildinfoformat {
	    short_f, long_f };

	wxString wxbuildinfo(wxbuildinfoformat format)
	{
	    wxString wxbuild(wxVERSION_STRING);

	    if (format == long_f )
	    {
	#if defined(__WXMSW__)
		wxbuild << _T("-Windows");
	#elif defined(__WXMAC__)
		wxbuild << _T("-Mac");
	#elif defined(__UNIX__)
		wxbuild << _T("-Linux");
	#endif

	#if wxUSE_UNICODE
		wxbuild << _T("-Unicode build");
	#else
		wxbuild << _T("-ANSI build");
	#endif // wxUSE_UNICODE
	    }

	    return wxbuild;
	}


	BEGIN_EVENT_TABLE(wxQuestionDialog, wxDialog)
	    EVT_CLOSE(wxQuestionDialog::OnClose)
	    EVT_BUTTON(idBtnGo, wxQuestionDialog::OnGo)
	END_EVENT_TABLE()

	wxQuestionDialog::wxQuestionDialog(wxDialog *dlg, const wxString &title)
	    : wxDialog(dlg, -1, title)
	{
	    this->SetSizeHints(wxDefaultSize, wxDefaultSize);
	    wxBoxSizer* bSizer1;
	    bSizer1 = new wxBoxSizer(wxHORIZONTAL);
	    m_staticText1 = new wxStaticText(this, wxID_ANY, wxT("Welcome To\nwxWidgets"), wxDefaultPosition, wxDefaultSize, 0);
	    m_staticText1->SetFont(wxFont(20, 74, 90, 90, false, wxT("Arial")));
	    bSizer1->Add(m_staticText1, 0, wxALL|wxEXPAND, 5);
	    wxBoxSizer* bSizer2;
	    bSizer2 = new wxBoxSizer(wxVERTICAL);

	    wxPoint textCtrl1Position(5,5); //Position
	    wxSize textCtrl1size(120,25); //Size
	    textCtrl1 = new wxTextCtrl(this, wxID_ANY, "hi", wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, "textCtrl1"); //Create textCtrl
	    bSizer2->Add(textCtrl1, 0, wxALL|wxEXPAND, 5); //Add to sizer

	    m_staticline1 = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL);
	    bSizer2->Add(m_staticline1, 0, wxALL|wxEXPAND, 5);
	    BtnGo = new wxButton(this, idBtnGo, wxT("&Go"), wxDefaultPosition, wxDefaultSize, 0);
	    bSizer2->Add(BtnGo, 0, wxALL, 5);
	    bSizer1->Add(bSizer2, 1, wxEXPAND, 5);
	    this->SetSizer(bSizer1);
	    this->Layout();
	    bSizer1->Fit(this);
	}


	wxQuestionDialog::~wxQuestionDialog()
	{
	}

	void wxQuestionDialog::OnClose(wxCloseEvent &event)
	{
	    Destroy();
	}

	void wxQuestionDialog::OnGo(wxCommandEvent &event)
	{
	    somefunction();
	}


otherFile.cpp:

1
2
3
4
5
6
7
	#include "wxQuestionMain.h"

	void somefunction()
	{
	    //Try to change the text in textCtrl1
	    wxQuestionDialog::textCtrl1->AppendText("Red text\n");
	}


Produces:

1
2
	error: ‘wxTextCtrl* wxQuestionDialog::textCtrl1’ is protected
	error: invalid use of non-static data member ‘wxQuestionDialog::textCtrl1’


So I moved 'wxTextCtrl* textCtrl1;' in 'wxQuestionMain.h' from 'protected' to 'public'

Produces:

error: invalid use of non-static data member ‘wxQuestionDialog::textCtrl1’

The class in wxQuestionMain.h seems to say 'class wxQuestionDialog: public wxDialog'

I don't know what that "public" part means, I've never seen a class be created like that before, but I'm going to try to change 'otherFile.cpp' so it sais wxDialog instead of wxQuestionDialog.

1
2
3
4
5
6
7
8
	#include "wxQuestionMain.h"
	#define BOOST_FILESYSTEM_VERSION 2

	void somefunction()
	{
	    //Try to change the text in textCtrl1
	    wxDialog::textCtrl1->AppendText("Red text\n");
	}


Produces:

error: ‘textCtrl1’ is not a member of ‘wxDialog’

I'm at a loss here.. how can I update the text in "textCtrl1" without adding "somefunction()" to the wxWidget class?

CodeBlocks auto generated 2 other files, not sure if they are important, but here they are.

wxQuestionApp.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
	#ifdef WX_PRECOMP
	#include "wx_pch.h"
	#endif

	#ifdef __BORLANDC__
	#pragma hdrstop
	#endif //__BORLANDC__

	#include "wxQuestionApp.h"
	#include "wxQuestionMain.h"

	IMPLEMENT_APP(wxQuestionApp);

	bool wxQuestionApp::OnInit()
	{
	    
	    wxQuestionDialog* dlg = new wxQuestionDialog(0L, _("wxWidgets Application Template"));
	    
	    dlg->Show();
	    return true;
	}


wxQuestionApp.h

1
2
3
4
5
6
7
8
9
10
11
12
	#ifndef WXQUESTIONAPP_H
	#define WXQUESTIONAPP_H

	#include <wx/app.h>

	class wxQuestionApp : public wxApp
	{
	    public:
		virtual bool OnInit();
	};

	#endif // WXQUESTIONAPP_H 
wxQuestionDialog::textCtrl1->AppendText("Red text\n")
Well, yeah. This is never going to work. wxQuestionDialog is just a type. For example:
1
2
wxQuestionDialog a;
wxQuestionDialog b;
How would the compiler know which object you want to use? Maybe you only ever create a single instance of wxQuestionDialog, but the compiler can't know this.

To do what you want to do, you need to pass the object you want to affect:
1
2
3
void somefunction(wxQuestionDialog &dialog){
     dialog.textCtrl1->AppendText("Red text\n");
}
But textCtrl1 is protected, so you won't be able to access it from some function. You should instead add a member function to wxQuestionDialog that looks something like this:
1
2
3
4
//TODO: Pick a better name. Use a better parameter type.
void wxQuestionDialog::AppendText_to_textCtrl1(const char *t){
    this->textCtrl1->AppendText(t);
}
And now somefunction() would do this:
 
dialog.AppendText_to_textCtrl1("Red text\n");
Last edited on
Thanks for your answer, but I don't quite understand what parameter to pass to somefunction(wxQuestionDialog &dialog).

I figured it was the
wxQuestionDialog* dlg = new wxQuestionDialog(0L, _("wxWidgets Application Template"));
line, inside wxQuestionApp.cpp

So I took that out of its function (wxQuestionApp::OnInit()) and instead put it in a header file that is included by all files. So now I call somefunction like this:
somefunction(dlg);

But that gives this error:
1
2
error: invalid initialization of reference of type ‘gfxDialog&’ from expression of type ‘gfxDialog*’
error: in passing argument 1 of ‘void somefunction(gfxDialog&)


What am I doing wrong this time? I simply assumed the "dlg" was the parameter to pass, as I couldn't find anything else that made sense.
So I took that out of its function (wxQuestionApp::OnInit()) and instead put it in a header file that is included by all files.
Don't do that.
Pass *this.

By the way, why don't you want somefunction() to be a member function of wxQuestionDialog?
Last edited on
Ok, I wanted to keep it simple but I'll be using my main application's code now to explain stuff (cutting unrelated stuff out). I'll keep the filenames the same to avoid confusion.

The class in the header:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class gfxDialog: public wxDialog
{
    public:
	/* Unrelated stuff */

        void AppendText_to_textCtrl1(const char *t);

    protected:
        enum
        {
		/* Unrelated stuff */
        };

        //NewTextCtrl
        wxTextCtrl* textCtrl1;

	/* Unrelated stuff */

    private:
	/* Unrelated stuff */

        void OnAbout(wxCommandEvent& event);

        DECLARE_EVENT_TABLE()
};


The function that handles the button click (in wxQuestionMain.cpp)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

struct torrentThreadStart
{
    torrentThreadStart(char* torrentURL,gfxDialog &dialog) : torrentURL(torrentURL),dialog(dialog) { }

    void operator()()
    {
        torrentDownloadOld(torrentURL,dialog);
    }
    char* torrentURL;
    gfxDialog &dialog;
};

void gfxDialog::OnAbout(wxCommandEvent &event)
{
    boost::thread_group group; //Create boost thread group (for later)

    std::string torrentURL = "/home/fulluser/Documents/gfx/bin/Debug/torrents/test.torrent"; //Torrent hard-coded atm for testing purposes

    torrentThreadStart startit((char*)torrentURL.c_str(),*this); //Create new torrentDownload function
    group.create_thread(startit); //Create a new thread for this function
}


As you can see, I am using a struct to create a Boost thread for a torrent download. Which is the reason I didn't want "somefunction()" (torrentDownloadOld() in this real application) to become part of wxQuestionDialog.

What happens now is that I can pass arguments to the libboost thread, which can then pass those arguments on to the function "torrentDownloadOld(torrentURL,dialog);".

otherFile.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
void gfxDialog::AppendText_to_textCtrl1(const char *t)
{
    this->textCtrl1->AppendText(t);
}

int torrentDownloadOld(char* torrentURL,gfxDialog &dialog)
{
	/* Unrelated stuff */

	dialog.AppendText_to_textCtrl1("Red text");

	return 0;
}


All of this is of course a setup to eventually be able to report to WxWidgets how our torrent download is progressing, because at the moment no progress is shown whatsoever. So when I get this working I will have to learn how to use that AppendText_to_textCtrl1 function to create progress bars for each torrent thread and stuff like that.

But it looks like I shot myself in the foot with this one because when I call "dialog.AppendText_to_textCtrl1("Red text");" the program crashes. Codeblocks reports nothing valuable (Process terminated with status -1). I'm going to go ahead and guess that doing this from a Boost::Thread is causing the crash.. although I am not sure (yet).

And thanks for your assistance by the way.. I have been stuck on this for days, which is a little demotivating ;)
Last edited on
As you can see, I am using a struct to create a Boost thread for a torrent download. Which is the reason I didn't want "somefunction()" (torrentDownloadOld() in this real application) to become part of wxQuestionDialog.
I don't see the connection. For example,
1
2
3
4
5
6
7
8
9
10
class Type{
//...
    void thread(int);
}

//...

Type t;
//The syntax may not be quite right, but the idea is possible with boost::bind.
boost::thread bt(boost::bind(Type::thread,t,some_int));


I'm going to go ahead and guess that doing this from a Boost::Thread is causing the crash.
Correct. GUI toolkits in general aren't designed to have their widgets accept asynchronous messages.
I had no idea boost::thread was capable of that, I will try it out soon.

But even if I do end up adding torrentDownloadOld() to wxQuestionDialog so I can update controls from within the function, WxWidget will still crash because it doesn't accept asynchronous messages? So basically; it doesn't really matter if I add the function to the class or use the struct, it's a personal preference?

Will I have to start doing things like this to post updates to the main thread? (looks painfully difficult)

http://wiki.wxwidgets.org/Inter-Thread_and_Inter-Process_communication#Sending_events_to_the_main_thread

Isn't there something simpler, similar to Visual Basic's delegates? If there's not, that's fine, just want to make sure I'm not wasting time on this stuff.

Sorry for asking you 4 questions at once, it's impossible to find these things using google.
Last edited on
But even if I do end up adding torrentDownloadOld() to wxQuestionDialog so I can update controls from within the function, WxWidget will still crash because it doesn't accept asynchronous messages? So basically; it doesn't really matter if I add the function to the class or use the struct, it's a personal preference?
Well, no, but it's a good thing to know anyway, isn't it?

Maybe you could avoid this by not using the thread at all. What are you using it for?
Last edited on
Each P2P transfer (each torrent) is assigned it's own thread this way. Even if I added them all in the same thread, it can't be the main thread.. the GUI would hang even on a single download.
Topic archived. No new replies allowed.