How can I update a progress bar? - winapi

How can I update this progress bar in win32api? You can find the full code here Code is here
hProgress=CreateWindowEx(0, PROGRESS_CLASS, NULL,
WS_CHILD | WS_VISIBLE,
20, 20, 260, 17,
hwnd, NULL, g_hInst, NULL);

The message you are looking for is PBM_SETPOS. The usage of this depends on what the range is currently set to (defaults from 0-100). For example, assuming the default range, setting the position to halfway would be done as so:
SendMessage(hProgress, PBM_SETPOS, 50, 0);
Alternatively, the progress bar can be incremented in steps through PBM_STEPIT. The usage of this depends on what the step increment is (default to 10). For example, assuming the default range and initial position of the progress bar, stepping the position to 10 would be done as so:
SendMessage(hProgress, PBM_STEPIT, 0, 0);

Assuming you have initialised common controls :
INITCOMMONCONTROLSEX InitCtrlEx;
InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
InitCtrlEx.dwICC = ICC_PROGRESS_CLASS;
InitCommonControlsEx(&InitCtrlEx);
Set the range:
SendMessage(hProgress, PBM_SETRANGE, 0, MAKELPARAM(min, max));
Set the position:
SendMessage(hProgress,PBM_SETPOS,pos,0);
See: MSDN docs

You could use the PMB_STEPIT message to move the current position based on the step size:
int max_range = 1000;
// set range of progress bar
SendMessage(hProgress, PBM_SETRANGE, 0, MAKELPARAM(0, max_range));
// set the step size
SendMessage(hProgress, PBM_SETSTEP, (WPARAM) 1, 0);
// increment by step size
SendMessage(hProgress, PBM_STEPIT, 0, 0);
Here is a good example How to Use Progress Bar Controls

In addition to updating the progress in the progress bar, you must also give it a chance to repaint. Usually you're showing a progress bar because you're busy working, and so the normal message loop isn't running and no WM_PAINT messages are generated. You can call UpdateWindow to repaint the window immediately.

Related

can't change the height of status bar control in a property page in win32

I have a windows application in which I am trying to create a status bar at the bottom of a PropertyPage. I have added a member variable of type CStatusBarCtrl named m_StatBar in the derived propertypage class.
Here is the code in the OnInitDialog of the PropertyPage
enter code here
int nTotWide; // total width of status bar
CRect rect3;
this->GetWindowRect(&rect3);
rect3.top = rect3.bottom - 70;
int m_bRvStatOk = m_StatBar.Create(WS_CHILD | WS_BORDER | WS_VISIBLE, rect3, this,IDC_STATUSBAR);
if (m_bRvStatOk == NULL)
{
AfxMessageBox("Status Bar not created!", NULL, MB_OK);
}
// get size of window, use to configure the status
// bar with four separate parts
nTotWide = rect3.right - rect3.left;
//
// Make each part 1/4 of the total width of the window.
//
m_Widths[0] = nTotWide / 4;
m_Widths[1] = nTotWide / 2;
m_Widths[2] = nTotWide - m_Widths[0];
m_Widths[3] = -1;
m_StatBar.SetMinHeight(70);
m_StatBar.SetParts(4, m_Widths);
m_StatBar.SetText("TEXT WITH BORDER.", 0, 0);
m_StatBar.SetText("TEXT WITHOUT BORDER.", 1, SBT_NOBORDERS);
m_StatBar.SetText("TEXT POPUP.", 2, SBT_POPOUT);
I am not able to change the height of the status bar.
appreciate any help on the same.
You cannot set the height of a status bar. However, you can request a minimum size by sending an SB_SETMINHEIGHT message to the control (which is what the CStatusBarCtrl::SetMinHeight implementation does).
This is not enough for the system to pick up the requested minimum height, though. While the MFC documentation doesn't provide any help or hint, the SB_SETMINHEIGHT documentation has the following remark:
An application must send the WM_SIZE message to the status window to redraw the window. The wParam and lParam parameters of the WM_SIZE message should be set to zero.
This translates to the following MFC implementation:
m_StatBar.SetMinHeight(70);
m_StatBar.SendMessage(WM_SIZE); // wParam and lParam have default arguments set to 0

MFC: Changing from CDialog to CWnd now the CStatusBar doesn't show?

To work around a problem with a CDialog being minimized when main window was minimized I decided to try using a CWnd instead. That works but now the CStatusBar doesn't show? What might I be missing or is there some requirement for it to show?
The new CWnd is created like this:
CString classname=AfxRegisterWndClass(CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, 0, 0, LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE (IDR_MAINFRAME)));
m_pDlgNowACWnd->CreateEx(0, classname, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CRect(0, 0, 0, 0), NULL, 0)
The initialization in OnInitDialog() now being OnCreate() does the nroaml m_StatusBar.Create(this) then initializes it further with:
EnableDynamicLayout(FALSE);
// set our own height so we can scale
CStatusBarCtrl &statusctrl=m_StatusBar.GetStatusBarCtrl();
statusctrl.SetMinHeight(g_DPIHelper.Scale(20));
m_StatusBar.SetIndicators(indicators, _countof(indicators));
m_StatusBar.SetPaneInfo (0, ID_SEPARATOR, SBPS_NORMAL|SBPS_STRETCH, 0);
m_StatusBar.SetPaneInfo (sliderPane, ID_SEPARATOR, SBPS_NORMAL, g_DPIHelper.Scale(128));
m_StatusBar.SetPaneInfo (textPane, ID_SEPARATOR, SBPS_NORMAL|SBPS_POPOUT, g_DPIHelper.Scale(30));
// add this to workaround the GetSystemMatrix() issue above.
m_StatusBar.SetPaneInfo (STATUSBARspacerPane, ID_SEPARATOR, SBPS_NORMAL, 25);
// this is needed to calc location and size of bar
RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, IDC_VIEW_ACHILDCWND);
EnableDynamicLayout();
auto pdlmanager=GetDynamicLayout();
if (pdlmanager) {
if (pdlmanager->Create(this)) {
pdlmanager->AddItem(m_CWndView.GetSafeHwnd(), CMFCDynamicLayout::MoveNone(), CMFCDynamicLayout::SizeHorizontalAndVertical(100, 100));
pdlmanager->AddItem(m_StatusBar.GetSafeHwnd(), CMFCDynamicLayout::MoveVertical(100), CMFCDynamicLayout::SizeHorizontal(100));
}
}
It's a status bar with a slider on it and some text.
The main CDialog now CWnd has two children a CWnd and a CStatusBar. The initial size of the dialog/window is 0, but then is resized to correct size when the dialog/window will be shown.
Any idea what I may be missing or doing wrong on converting from CDialog to a CWnd ?
Everything else works, just the CStatusBar not showing?
Thanks.
Update:
It appears to be the CStatusBar height being zero. I did a test of creating the CWnd being CRect(0, 0, 10, 50) instead of all zeros and the CStatusBar shows (although with a height of 11 which is much shorter than it should be). It seems the statusctrl.SetMinHeight(g_DPIHelper.Scale(20)) call doesn't work when using CWnd? The resizing takes place in RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, IDC_VIEW_ACHILDCWND); I set a breakpoint on CStatusBar::OnSize() and noticed when a CDialog it had the correct size but not with CWnd(had zero originally now 11 with using a height of 50 on the CWnd Create()).
Since the height of the CStatusBar won't change once created and calculated during OnCreate() the size of the created CWnd needs to be tall enough for the desired CStatusBar minimum height. So instead of this:
m_pDlgNowACWnd->CreateEx(0, classname, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CRect(0, 0, 0, 0), NULL, 0);
Do this:
CRect rccreate(0, 0, 0, MYDLG_STATUSBAR_MINHEIGHT);
CalcWindowRect(&rccreate);
m_pDlgNowACWnd->CreateEx(0, classname, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, rccreate, NULL, 0);

How to detect screen resize events coming from ncurses in QNX?

I can not configure to receive events about changing the size of the terminal using ncurses QNX Momentics.
I am using Putyy as a terminal and data is transmitted through the COM port.
My question is how to realize the reception of screen change events when using a remote terminal?
FILE* fcons = fopen("/dev/ser1", "r+");
SCREEN* term = newterm("xterm-r5", fcons, fcons);
int y = 0, x = 0;
//if(y < 24 || x < 80)
// resizeterm(24, 80);
flushinp();
main_scr = newwin(24, 80, 0, 0);
head_scr = subwin(main_scr, 3, 80, 0, 0);
prompt_scr = subwin(main_scr, 1, 9, 3, 2);
cursor_scr = newwin(1, 60, 3, 6);
output_scr = subwin(main_scr, 18, 76, 5, 2);
keypad(cursor_scr, TRUE);
int f = mousemask(ALL_MOUSE_EVENTS, NULL);
chtype temp_ch = 0;
while(KEY_RESIZE == temp_ch)
temp_ch = wgetch(cursor_scr);
return 0;
A plain serial-port connection like that won't send a SIGWINCH. In other configurations, e.g., telnet, that's done as a result of NAWS (negotiations about window size--I dont't see a duplicate). Your application could poll for this by doing what the resize program does, plus a little more, e.g.,
save the cursor-position
move the cursor to a very-far-off lower-right corner
ask the terminal where the cursor really is
wait for the response, to get the actual screensize
set the terminal's screensize using a system call
restore the cursor position
send a SIGWINCH to yourself
Unlike resize, that would be done inside your program, so it would have to save/restore the cursor position (to avoid confusing ncurses). Keep in mind that ncurses has set the terminal to raw mode, so that part of the initialization would not be needed.

Can't change tooltip coordinates MFC

I need to make tooltip a little bit right and lower to mouse cursor, but i can't do it in any way, tried different coordintaes but nothing seems to work. Where is the problem? Thank you.
// Add the new tooltip (if available)
if (m_LastToolTipRow!=-1 && m_LastToolTipRow!=-1)
{
// Not using CToolTipCtrl::AddTool() because it redirects the messages to CListCtrl parent
TOOLINFO ti = {0};
ti.cbSize = sizeof(TOOLINFO);
ti.uFlags = TTF_IDISHWND | TTF_TRANSPARENT; // Indicate that uId is handle to a control
ti.uId = (UINT_PTR)m_hWnd; // Handle to the control
ti.hwnd = m_hWnd; // Handle to window to receive the tooltip-messages
ti.hinst = AfxGetInstanceHandle();
ti.lpszText = LPSTR_TEXTCALLBACK;
m_OwnToolTipCtrl.SendMessage(TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
m_OwnToolTipCtrl.SendMessage(TTM_TRACKPOSITION, 0, (LPARAM)MAKELPARAM(pt.x + 100, pt.y + 100));
m_OwnToolTipCtrl.SendMessage(TTM_TRACKACTIVATE, true, (LPARAM)&ti);
m_OwnToolTipCtrl.Activate(TRUE);
//Multiline
m_OwnToolTipCtrl.SetMaxTipWidth(256);
//m_OwnToolTipCtrl.SetMaxTipWidth(SHRT_MAX);
}
TTF_IDISHWND
Indicates that the uId member is the window handle to the tool. If this flag is not set, uId is the tool's identifier.
According to this, the window with m_hWnd handle is the one that shows the tooltip and you can position the window itself. If you meant a tooltip separate to that window than there is a principal problem there.

Win32 API: How to scroll down automatically a text inside EDIT control?

I have an EDIT control created like this:
hwndEDIT_5 = CreateWindowEx (
0, "EDIT", NULL,
WS_VSCROLL | WS_BORDER | WS_VISIBLE | WS_CHILD | ES_MULTILINE | ES_READONLY,
135, 450, 555, 200,
h2, ( HMENU ) ID_EDIT_CONSOLE,
h1, NULL
);
As you can see it is a read-only EDIT area where multi lines text can be displayed. It is supposed to be a console where I can display some information for users when they use the program. I would like the text area to automatically scroll to the bottom-most entry (the newest one) whenever a new line (or message for an user) is added. I've implemented this:
SetDlgItemText ( h2, ID_EDIT_CONSOLE, ch_s );
SCROLLINFO scr;
SCROLLINFO * scr_p = &scr;
scr.cbSize = sizeof ( SCROLLINFO );
scr.fMask = SIF_RANGE;
GetScrollInfo ( GetDlgItem ( h2, ID_EDIT_CONSOLE), SB_VERT, scr_p );
int mmax = scr.nMax;
scr.fMask = SIF_POS;
scr.nPos = mmax;
SetScrollInfo ( GetDlgItem ( h2, ID_EDIT_CONSOLE), SB_VERT, scr_p, TRUE );
That code is scrolling vertical scrollbar to the end of an EDIT control after adding new msg and it works great, the scrollbar gets scrolled but the text still remains visible from the beginning - it rewinds to the beginning after addition while scrollbar rewinds to the bottom. How to make it properly?
Last but not least - this is might be important - in order to display a message firstly I capture the text that is already displayed by using:
GetDlgItemText ( h2, ID_EDIT_CONSOLE, buf, len + 1 );
then I convert buf into string and add to that string a new message that I want to display. Then I convert it back to char array and set it up with SetDlgItemText. I seperate lines by using \r\n. I've coded it that way because I didn't know how to add a line to an EDIT control in different way than using SetDlgItemText. And it adds only one entry AFAIK - if used twice I will not come up with two entries added to an EDIT control, but the first one will get replaced by second function call.
Don't use SetScrollInfo. Use SendMessage() with the EM_LINESCROLL message, sending the message to the edit control's window handle.
SendMessage(MemoHwnd, EM_LINESCROLL, 0, NumLinesToScroll);
The documentation says:
The control does not scroll vertically past the last line of text in the edit control. If the current line plus the number of lines specified by the lParam parameter exceeds the total number of lines in the edit control, the value is adjusted so that the last line of the edit control is scrolled to the top of the edit-control window.
I had the same problem and solved it with Jerry Coffin's answer and some research.
This is the way I use now:
string text = "Append this text";
SendMessageA(hEdit, EM_SETSEL, 0, -1); //Select all
SendMessageA(hEdit, EM_SETSEL, -1, -1);//Unselect and stay at the end pos
SendMessageA(hEdit, EM_REPLACESEL, 0, (LPARAM)(text.c_str())); //append text to current pos and scroll down
If needed: To scroll at the end of Edit Control without appending text:
SendMessageA(hEdit, EM_SETSEL, 0, -1); //Select all.
SendMessageA(hEdit, EM_SETSEL, -1, -1);//Unselect and stay at the end pos
SendMessageA(hEdit, EM_SCROLLCARET, 0, 0); //Set scrollcaret to the current Pos
You can add text by setting the beginning and end of the selection to the end of the text in the control (EM_SETSEL), then replacing the (empty) selection with your new text (EM_REPLACESEL).
Scrolling to the bottom can be done with EM_SCROLLCARET after the caret (the selection) is at the end of the text. There are other ways, but if you're doing it immediately after adding text, this is probably the easiest.
in my case I had a multi line string and Ken White's idea worked very well:
HWND hEdit = this->GetDlgItem(IDC_EDIT_LOG)->m_hWnd;
if (hEdit)
{
int lineCount = m_strClientLog.Replace(_T("\n"), _T("\n"));
::SendMessage(hEdit, EM_LINESCROLL, 0, lineCount);
}
for MFC projects you can use:
mLoggingTextCtl.SendMessage(EM_SETSEL, 0, -1); //Select all.
mLoggingTextCtl.SendMessage(EM_SETSEL, -1, -1);//Unselect and stay at the end pos
mLoggingTextCtl.SendMessage(EM_SCROLLCARET, 0, 0); //Set scrollcaret to the current Pos

Resources