How to place wxGauge on the status bar (wxStatusBar) 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.
Post Reply
katuday
Earned some good credits
Earned some good credits
Posts: 134
Joined: Fri Aug 17, 2012 2:22 am

How to place wxGauge on the status bar (wxStatusBar)

Post by katuday »

I have seen this type of question asked but I am unable to find an example that I can easily follow.
There a fair amount of Python code doing this but I don't understand Python.
Here is what I have done so far:

Code: Select all

	// status bar constructor
	m_statusbar = new wxStatusBar(this, wxID_ANY, wxST_SIZEGRIP | wxNO_BORDER);
	m_statusbar->SetFieldsCount(5); // all fields will have text values except the second where I want the wxGauge
	SetStatusBar(m_statusbar);
	
	// place wxGauge on the status bar
	wxRect rect;
	m_statusbar->GetFieldRect(1, rect);
	m_progress = new wxGauge(m_statusbar, ID_QUERY_PROGRESS, 0, rect.GetPosition(), rect.GetSize(), wxGA_SMOOTH);
	
	// start timer
	m_timer = nullptr;
	m_timer = new wxTimer(this, ID_QUERY_PROGRESS_TIMER);
	m_timer->Start(300);
	
	// handle timer events
	Bind(wxEVT_TIMER, &MyFrame::progressTimer, this, ID_TIMER);
	
	void MyFrame::progressTimer(wxTimerEvent& WXUNUSED(evt))
	{
		m_progress->Pulse();
	}
	// handle re-sizing
	Bind(wxEVT_SIZE, &MyFrame::sizeChanged, this, ID_PROGRESS);
	void MyFrame::sizeChanged(wxSizeEvent& evt)
	{
		wxRect rect;
		m_statusbar->GetFieldRect(1, rect);
		m_progress->SetSize(rect);
		evt.Skip();
	}
Problems:
1) The layout of the wxGauge is wrong. I want it in the second field, but it appears in the first.
2) The call to m_progress->Pulse() does not produce any change in the wxGauge. However, I am sure the event is firing.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to place wxGauge on the status bar (wxStatusBar)

Post by doublemax »

1) The layout of the wxGauge is wrong. I want it in the second field, but it appears in the first.
I think the size event handler is not called because of:

Code: Select all

Bind(wxEVT_SIZE, &MyFrame::sizeChanged, this, ID_PROGRESS);
You're catching the size event of the frame, but the frame does not have the ID=ID_PROGRESS. Leave the ID out (or use wxID_ANY).
2) The call to m_progress->Pulse() does not produce any change in the wxGauge. However, I am sure the event is firing.
Are you sure the event is firing? Because i see a similar problem as above, the ID of the timer does not match the one in the Bind() call. Use the same ID in both calls and the timer event should work.

Code: Select all

m_timer = new wxTimer(this, ID_QUERY_PROGRESS_TIMER);
...
Bind(wxEVT_TIMER, &MyFrame::progressTimer, this, ID_TIMER);

Code: Select all

m_progress = new wxGauge(m_statusbar, ID_QUERY_PROGRESS, 0, rect.GetPosition(), rect.GetSize(), wxGA_SMOOTH);
You're creating the wxGauge with a max value of "0". Set something like 100 and you should see it pulse.

BTW: For checking if an event handler is called, using simple "printf-style" debugging can be useful.

Code: Select all

void MyFrame::sizeChanged(wxSizeEvent& evt)
{
   wxLogDebug("sizeChanged called");
   ...
}
Under Windows you can use a tool like "DebugView" to see the outputs of the wxLogDebug calls:
https://technet.microsoft.com/en-us/sys ... gview.aspx
(The application has to be build in debug-mode, in release mode the wxLogDebug calls are ignored)
Use the source, Luke!
katuday
Earned some good credits
Earned some good credits
Posts: 134
Joined: Fri Aug 17, 2012 2:22 am

Re: How to place wxGauge on the status bar (wxStatusBar)

Post by katuday »

doublemax wrote:think the size event handler is not called because of:

Code: Select all

Bind(wxEVT_SIZE, &MyFrame::sizeChanged, this, ID_PROGRESS);
You're catching the size event of the frame, but the frame does not have the ID=ID_PROGRESS. Leave the ID out (or use wxID_ANY).
Correct. The ID actually belonged to wxStatusBar, I thought I should be catching the size event of the status bar. Removing the ID completely gets me the expected behaviour
Are you sure the event is firing? Because i see a similar problem as above, the ID of the timer does not match the one in the Bind() call. Use the same ID in both calls and the timer event should work.
This was a mix up in copy pasting the actual code to my post. The ID was the same in my code and the event was firing ( I verified ).

Something I noticed though is that I actually don't need a timer. Calling Pulse once is enough. Then I need to call SetValue(0) to stop the gauge when the activity is complete. Since I only need indeterminate behavior this setup seems sufficient. Did I miss something?
My final code looks like this:

Code: Select all

MyFrame::MyFrame( ....
{
	.....
	wxRect rect;
	m_statusbar->GetFieldRect(1, rect);
	m_progress = new wxGauge(m_statusbar, ID_GAUGE, 100, rect.GetPosition(), rect.GetSize(), wxGA_SMOOTH);
}	
void MyFrame::startQueryProgress()
{
	m_progress->Pulse();
} 

void MyFrame::stopQueryProgress()
{ 
	m_progress->SetValue(0);
}
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to place wxGauge on the status bar (wxStatusBar)

Post by doublemax »

Something I noticed though is that I actually don't need a timer. Calling Pulse once is enough. Then I need to call SetValue(0) to stop the gauge when the activity is complete. Since I only need indeterminate behavior this setup seems sufficient. Did I miss something?
I didn't know that, but i just tested it and you're right. So much the better. It's possible that this doesn't work under XP though, but i didn't test that.
Use the source, Luke!
itachiboi999
Knows some wx things
Knows some wx things
Posts: 33
Joined: Mon Nov 15, 2021 7:06 pm

Re: How to place wxGauge on the status bar (wxStatusBar)

Post by itachiboi999 »

doublemax wrote: Fri Mar 25, 2016 2:33 pm
Something I noticed though is that I actually don't need a timer. Calling Pulse once is enough. Then I need to call SetValue(0) to stop the gauge when the activity is complete. Since I only need indeterminate behavior this setup seems sufficient. Did I miss something?
I didn't know that, but i just tested it and you're right. So much the better. It's possible that this doesn't work under XP though, but i didn't test that.
Hey, is there a way to exclusively keep a wxGauge within a partition on the status bar? currently when I resize my main wxFrame smaller than the origin size the partition on the right gets hidden by the wxGauge to the left of it

Code: Select all

//implement status bar
	const int SIZE = 3;
	statusbar = CreateStatusBar(SIZE);  // create a status bar with 3 partitions
	statusbar->SetStatusText(_("Online Version"), 2);
	int widths[SIZE] = { -3, -3, -1 };  //this says to make the second partition twice the size of the first
	statusbar->SetStatusWidths(SIZE, widths);

	//put loading gauge in status bar
	wxRect rect;
	statusbar->GetFieldRect(1, rect);
	progress = new wxGauge(statusbar, 10006, 100, rect.GetPosition(), rect.GetSize(), wxGA_SMOOTH);
Image

Image
Attachments
StatusBarPartition__2.PNG
StatusBarPartition__2.PNG (2.85 KiB) Viewed 861 times
StatusBarPartition.PNG
StatusBarPartition.PNG (4.33 KiB) Viewed 861 times
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to place wxGauge on the status bar (wxStatusBar)

Post by doublemax »

You need to catch the wxEVT_SIZE event of the frame and recalculate size and position of the wxGauge every time.

In the "statbar" sample that comes with wxWidgets, check the method MyStatusBar::OnSize(). It shows how it's done.
Use the source, Luke!
Post Reply