c++ winapi: Move scrollbar after WM_SETTEXT to old position - c++

I have this situation. I have two multiple line edit boxes. First is not editable and second yes. I catch EN_UPDATE message and when appears than I send updated text from second window to first window. So both of window have same text. Also If one is scrolled, than second one is scrolled too (mirrored behaviour).
Problem is that if I update text in first window after send new text from second window than scrollbar is moved at the start. If I use SetScrollPos than scrollbar is set, but text is not moved to correct position. I see the first line of text and I want to see position before update the text. How is this possible?
Update
I want that after SendMessage to first window like this to not to move window to the start position of text when replaced old text with new text. Because I have for example first window scrolled in the middle and after text is replaced that firstwindow is moved to the first line of new text but I want to stay in old position because I am updating only on letter in text in second window and than I send this change to firstWindow. But I resend all text.
SendMessage(firstWindow, WM_SETTEXT, 0, (LPARAM) buffer);
I create multiline text box like this:
firstWindow = CreateWindowEx(
0, TEXT("EDIT"), // predefined class
NULL, // no window title
WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER |
ES_READONLY | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,
TEXTBOX_START_X, TEXTBOX_START_Y, TEXTBOX_WIDTH, TEXTBOX_HEIGHT,
hWnd, // parent window
(HMENU) ID_TEXTBOX, // edit control ID
(HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE),
NULL
);
savedWndProcTablet = (WNDPROC) SetWindowLongPtr(tabletWindowUtils.textboxHwnd, GWL_WNDPROC, (LONG_PTR) &textBoxProc);
Update 2
I try this:
char *buffer = new char[2];
buffer = "a\0";
DWORD l,r;
SendMessage(secondWindow, EM_GETSEL,(WPARAM)&l,(LPARAM)&r);
SendMessage(firstWindow, EM_REPLACESEL, 0, (LPARAM)buffer);
SendMessage(firstWindow, EM_SETSEL,l,r);
So I have some text in first window and where is position in second window I add new letter to this position. But this add one letter to correct position but it add no one letter but still adds aaaaaaaaaaaaaaaa. Why is it doing?
I can use only pure c++ and winapi.
Thanks.

If you want to copy consistently the whole text from second edit box to first, and ensure that scrolling position is correctly mirrored, you can just use:
// get the full text of second window
int len = ::GetWindowTextLength(secondWindow) + 1;
LPTSTR txt = new TCHAR[len];
::GetWindowText(secondWindow, txt, len);
// copies it to first one
::SetWindowText(firstWindow, txt);
// get scroll position of second window
SCROLLINFO si = { sizeof(SCROLLINFO) };
::GetScrollInfo(secondWindow, SB_VERT, &si);
// set scroll bar of first window accordingly
::SetScrollInfo(firstWindow, SB_VERT | SIF_PAGE | SIF_POS | SIF_RANGE, &si, TRUE );
// get first visible line in second window
int line = ::SendMessage(secondWindow, EM_GETFIRSTVISIBLELINE, 0, 0);
// skip to same line in first window
::SendMessage(firstWindow, EM_LINESCROLL, 0, line);
delete[] txt;
You could of course copy only a part of the text using EM_REPLACESEL, but you did not say how to find the new and old part, so I proposed to replace everything.

Related

Who should be the parent of a tab control child dialog?

According to some sources, a tab child dialog should be the child of the actual main dialog window, not the tab control itself. I think some of the docs suggest the opposite, namely this function example:
// Creates a child window (a static control) to occupy the tab control's
// display area.
// Returns the handle to the static control.
// hwndTab - handle of the tab control.
//
HWND DoCreateDisplayWindow(HWND hwndTab)
{
HWND hwndStatic = CreateWindow(WC_STATIC, L"",
WS_CHILD | WS_VISIBLE | WS_BORDER,
100, 100, 100, 100, // Position and dimensions; example only.
hwndTab, NULL, g_hInst, // g_hInst is the global instance handle
NULL);
return hwndStatic;
}
So is there a definitive view on this? I checked Petzold, by the way, but didn't locate anything on the subject. Thanks for any help.

How To Draw Multi Column ListView in WM_DRAWITEM

I have a 3-column ListView (I didn't include the columns and items insertion code below since these parts work):
hwndListbox = CreateWindow(
WC_LISTVIEW,
"",
WS_VISIBLE | WS_BORDER | WS_CHILD | LVS_REPORT|LVS_OWNERDRAWFIXED,
100, 100,600, 300,
hwnd,
(HMENU)1,
NULL,
NULL);
Now I am trying to use WM_DRAWITEM to change the background colors based on the text in the 1st column:
case WM_DRAWITEM:
{
LPDRAWITEMSTRUCT pDIS = (LPDRAWITEMSTRUCT)(lParam);
HDC hDC = pDIS->hDC;
RECT rc = pDIS->rcItem;
// initialize brushes
HBRUSH bgRed = CreateSolidBrush (RGB(255,0,0));
HBRUSH bg = (HBRUSH)(GetStockObject(WHITE_BRUSH));
// declare strings for the sub-items' text
TCHAR text_col1[256];
TCHAR text_col2[256];
TCHAR text_col3[256];
// get the text from sub-items
ListView_GetItemText( pDIS -> hwndItem , pDIS -> itemID , 0 ,text_col1, 256);
ListView_GetItemText( pDIS -> hwndItem , pDIS -> itemID , 1 ,text_col2, 256);
ListView_GetItemText( pDIS -> hwndItem , pDIS -> itemID , 2 ,text_col3, 256);
// fill the row
if(strcmp(text_col1,"Random_Name") == 0)
{
FillRect(hDC,&rc,bgRed);
}
else
{
FillRect(hDC,&rc,bg);
}
// How to draw text of 2nd and 3rd columns within columns' boundaries?
DrawText(hDC, text_col1, strlen(text_col1), &rc, DT_SINGLELINE|DT_LEFT);
}
return 0;
How do I draw the text of 2nd and 3rd columns? I can call DrawText() with the other strings, but since they're all drawn onto the same rectangle, they don't conform to the column boundaries, but instead move freely across the rectangle depending on the format flags I specify in the last argument. How do I overcome this issue?
If there is a way to either get the same effect without using WM_DRAWITEM, or alternatively, define each column as a separate rectangle or any other solution, I'd love to hear.
You can use ListView_GetSubItemRect macro to retrieve subitem's rect.
void ListView_GetSubItemRect(
hwnd,
iItem,
iSubItem,
code,
prc
);

c++ win32 edit box cursor not flashing

I'm a newbie in windows programming and am continuously running into different kinds of problems, most of which I have been able to solve by myself.
My problem at hand is the caret (or cursor) shown in text areas. The thing that indicates where you are typing your text? Well it is shown, at least, but it doesn't blink like it should.
I have an EDIT box created in WM_CREATE like so:
case WM_CREATE:
{
if(!logged) {
HWND userField = CreateWindow(
"EDIT", // Predefined class; Unicode assumed
NULL, // Button text
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_LEFT, // Styles
C_WIDTH/2 - 80, // x position
C_HEIGHT - 240, // y position
160, // Button width
25, // Button height
hwnd, // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
NULL); // Pointer not needed.
// initialize NONCLIENTMETRICS structure
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(ncm);
// obtain non-client metrics
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
// create the new font
HFONT hNewFont = CreateFontIndirect(&ncm.lfMessageFont);
// set the new font
SendMessage(userField, WM_SETFONT, (WPARAM)hNewFont, 0);
}
}
break;
That is all code concerning the edit box. I'm sorry if I'm not being clear enough or my supply of code is lacking; I'm unsure of what parts of code is relevant here and what are irrelevant. I don't think I should paste my whole code here, either.
The problem, again, is that the caret in the textbox (userField) does not blink.
Please ask for more details if you need them.
Using your code, I didn't get a flashing caret. But then i added:
SetFocus( userField );
and voilà, a flashing caret :-)
This may not be the problem the OP was experiencing, but I was experiencing the same symptom, and I'm posting my solution here in case someone else experiences this problem...
In short, if you subclass an edit control, and handle the WM_SETFOCUS event, you need to call DefSubclassProc() or your caret won't show up. Presumably, you can call ShowCaret() yourself, but you're probably safer just calling DefSubclassProc() in case there's other processing that needs to happen.
After playing around - making my code a bit tidier and stuff - I accidentally solved this on my own
I changed
HWND userField = CreateWindow(
"EDIT", // Predefined class; Unicode assumed
NULL, // Button text
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_LEFT, // Styles
C_WIDTH/2 - 80, // x position
C_HEIGHT - 240, // y position
160, // Button width
25, // Button height
hwnd, // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
NULL); // Pointer not needed.
Into
HWND userField = CreateWindow("EDIT", NULL, WS_VISIBLE | WS_CHILD | WS_BORDER | ES_LEFT,
C_WIDTH/2 - 80, C_HEIGHT - 240, 160, 25, hwnd, NULL, g_hInstance, NULL);
The only difference there is the hInstance: in the first code it was apparently wrong. I changed it into my global reference of hInstance.

DialogBoxIndirect creates dialog bigger than asked

For my application I need to create a Dialog Box without using resource.
I am trying to do it with DialogBoxInderect function.
The code is unbelievably ugly but somehow I succeeded to do it.
The problem is that dialog, for some reason, is much bigger than I asked with much bigger fonts.
Here is how the dialog looks like if I load it from resource:
And here is the dialog with the same size stated when I call DialogBoxInderect function.
Here is how it is defined in code:
HGLOBAL hGlobal;
LPDLGTEMPLATE wlsDialogTemplate;
LPDLGITEMTEMPLATE wlsDialogItemTemplate;
LPWORD nextItem;
LPWSTR itemString;
int32_t itemStringLength;
// Check for memory allocation errors
hGlobal = GlobalAlloc(GMEM_ZEROINIT, 1024);
if (!hGlobal)
return -1;
wlsDialogTemplate = (LPDLGTEMPLATE)GlobalLock(hGlobal);
// Define a dialog box.
wlsDialogTemplate->style = WS_CAPTION;
wlsDialogTemplate->x = 0;
wlsDialogTemplate->y = 0;
wlsDialogTemplate->cx = 320;
wlsDialogTemplate->cy = 115;
GlobalUnlock(hGlobal);
retCode = DialogBoxIndirect(0, (LPDLGTEMPLATE)hGlobal, 0, ActivateWlsMsgDialog);
And here is how it is defined in RC file:
IDD_WLS_SMALL_MESSAGE_DLG DIALOGEX 0, 0, 320, 115
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",ID_CUSTOM_OK,175,95,120,15
PUSHBUTTON "Cancel",ID_CUSTOM_CANCEL,45,95,120,15
CTEXT "Static",IDC_HEADER_TEXT,120,10,170,70
CONTROL "",IDC_LOGO,"Static",SS_BITMAP,16,10,83,70
END
As you can see, the second dialog is much bigger than defined. I tried to play with various style flags but without any success (That is why there is red cross on the bigger dialog).
Any help with that?
Thanks!
The larger size is easy to explain. Windows automatically sizes the dialog in accordance with its font, and the larger dialog uses a different font. In fact, it is using the default system font (more info on the confusing issue of Windows dialog fonts is found in my answer here).
So the real issue to focus on is why it's using a different font, and fixing that will solve the size problem.
In the dialog box resource file, you specify the DS_SETFONT flag as one of the dialog box styles. According to the documentation, this flag
[i]ndicates that the header of the dialog box template (either standard or extended) contains additional data specifying the font to use for text in the client area and controls of the dialog box. If possible, the system selects a font according to the specified font data. The system passes a handle to the font to the dialog box and to each control by sending them the WM_SETFONT message.
So that explains why that one is displaying with the expected font.
The next logical question is what's different about your dynamically-created dialog template, shown with the DialogBoxIndirect function. The culprit is, once again, the DS_SETFONT flag, but in this case, the flag is absent. That means that the dialog doesn't contain any information about which font to use to display its controls, and the system defaults to the default system font (which is the ugly Windows 2.0-era font that you see in the second screenshot).
Once we've come to this understanding, the solution should be obvious: you need to tell the dialog which font you want it to use. There are two possible ways of doing so that come to mind:
You can set the DS_SETFONT flag and provide the font information in the header of the dialog box template as described in the above-linked documentation.
Or you can simply create and set the dialog's font in response to the WM_INITDIALOG message.
The latter is probably what you really want to do, as it allows you to use the actual system font (which, confusingly, is different from what I've been calling the "default" system font), which is Segoe UI in Windows Vista and later. Note that even in your first screenshot, it's using MS Sans Serif and therefore sticks out like a sore thumb in the Aero interface. Again, see this answer for more about fonts than you ever wanted to know and sample code for making this work. You'll need to make sure that you set the font for the dialog itself and all of its child controls.
I had played with DialogBoxIndirect (actually with DialogBoxIndirectParam), and here's the part of the code that sets the font. Observe the DS_SHELLFONT option.
LPWORD lpwAlign(LPWORD lpIn, int nAlignment)
{
return (LPWORD)(((ULONG_PTR)lpIn + nAlignment - 1) & -nAlignment);
}
LRESULT DisplayMyMessage(HINSTANCE hinst, HWND hwndOwner, LPMYMESSAGEPARAMS pParams)
{
WORD mem[1024]; // Buffer for dialog resource
LPDLGTEMPLATEW lpdt; // Pointer to heading resource structure
LPDLGITEMTEMPLATEW lpdit; // Pointer to current control
LPWORD lpw; // Cursor to resource buffer
LPWSTR lpwsz; // Cursor to resource buffer (of type WCHAR)
LPCWSTR lpwszCaption; // Aux pointer for text copying
LRESULT ret; // Function's return value
lpdt = (LPDLGTEMPLATEW)lpwAlign( mem, 4 );
//-----------------------
// Define a dialog box.
//-----------------------
lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION |
DS_MODALFRAME | DS_CENTER | DS_SHELLFONT;
lpdt->dwExtendedStyle = 0;
lpdt->cdit = 3; // number of controls
lpdt->x = 0; lpdt->y = 0;
lpdt->cx = 164; lpdt->cy = 49;
lpw = (LPWORD)(lpdt + 1);
// Dialog menu
*lpw++ = 0;
// Dialog class
*lpw++ = 0;
// Dialog title
for (lpwsz = (LPWSTR)lpw, lpwszCaption = L"Choose language";
*lpwsz++ = *lpwszCaption++;
);
lpw = (LPWORD)lpwsz;
// Dialog font
if ( lpdt->style & (DS_SETFONT | DS_SHELLFONT) )
{
// Size
*lpw++ = 8;
// Typeface name
for (lpwsz = (LPWSTR)lpw, lpwszCaption = L"MS Shell Dlg";
*lpwsz++ = *lpwszCaption++;
);
lpw = (LPWORD)lpwsz;
}
// Define the rest of the controls
...
ret = DialogBoxIndirectParamW( hinst, lpdt,
hwndOwner, MyMessageProc, (LPARAM)pParams );
return ret;
}
This can be solved in your dialog handler by looking for the WM_INITDIALOG message, and then setting the font for all the controls in the dialog.
int CALLBACK SetChildFont(HWND child, LPARAM font) {
SendMessage(child, WM_SETFONT, font, TRUE);
return TRUE;
}
static int CALLBACK MyMessageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_INITDIALOG:
/* Set font for dialog and all child controls */
EnumChildWindows(hwnd, (WNDENUMPROC)SetChildFont, (LPARAM)GetStockObject(DEFAULT_GUI_FONT));
break;
}
return 0;
}

How to print bold string in C++?

I got an old application which was written in a C++. I have 0 experience with it but I am suppose to make some changes in app. One of them is to change some text. Problem is that part of updated text needs to be bold, but i have no idea how to do that. I googled but with no much success. Only think I now is to go to new line with \nand new tab with \t.
Any clever advise?
EDIT:
Example of code:
BEGIN
STRING1 "First Example"
STRING2 "Second Example"
And place where STRING1 is used:
// WelcomeTip ---------------------------------------------//
LPSTR idsWelcomeTip = (LPSTR)GlobalAlloc(GPTR, sizeof(CHAR) * 4098 );
LoadString( waveInDlg->hInstance, STRING1, idsWelcomeTip, 4098 );
waveInDlg->hwndWelcomeTip = CreateWindow(
"STATIC",
idsWelcomeTip,
WS_CHILD | WS_VISIBLE | SS_LEFT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
waveInDlg->hwnd,
NULL,
waveInDlg->hInstance,
NULL
);
SetWindowLongPtr(waveInDlg->hwndWelcomeTip, GWLP_USERDATA ,(LONG)waveInDlg );
SendMessage(waveInDlg->hwndWelcomeTip, WM_SETFONT , (WPARAM)waveInDlg->hFontDefault , TRUE );
ShowWindow(waveInDlg->hwndWelcomeTip, SW_HIDE);
GlobalFree( (HGLOBAL)idsWelcomeTip );
Thanks,
Ile
There is no concept of bold text in C++, there may be in a particular device that displays character text, for example rich-text-format or HTML tagging or a terminal screen. The latter usually involves sending some "escape sequence" relevant to that particular terminal.
OK, I've knocked up some code that should give an overview of what you're after, I've not managed to compile it as I'd need to write a lot more to test, but it should point you in the right direction:
// Create the font you need
LOGFONT lf;
zeromemory(&lf, sizeof(LOGFONT))
lf.lfHeight = 20; // 20 pixel high font
lf.lfWeight = FW_BOLD;
strcpy(lf.lfFaceName, "Arial");
HFONT hFont = ::CreateFondIndirect(&lf);
// Set the control to use this font
SendMessage(waveInDlg->hwndWelcomeTip, WM_SETFONT, (WPARAM)hFont, NULL);
I hope this helps.
Please go through the below link for help
http://msdn.microsoft.com/en-us/library/dd162499(VS.85).aspx
Yes, you have to override WM_PAINT in your dialog class and call drawtext function.
Use DrwaText API in WM_PAINT message handler.dc.DrawText (_T ("Hello, MFC"), -1, &rect,
DT_SINGLELINE ¦ DT_CENTER ¦ DT_VCENTER);
use DrawTextEx method.
For more inforamtion go through the follwoing link
ms-help://MS.MSDNQTR.v90.en/gdi/fontext_4pbs.htm