Jump to content
MSFN is made available via donations, subscriptions and advertising revenue. The use of ad-blocking software hurts the site. Please disable ad-blocking software or set an exception for MSFN. ×

WINAPI: Riched20 control on tab control drawing


Recommended Posts

I'm programming a small application that has a tab control with riched20 controls on it. When it first starts, there are no controls in the main window. Here's what happens:

  • I choose to open a file through the open file dialog
  • If the tab control doesn't exist yet, it is created and made to fill the entire window
  • A tab is added to the tab control
  • A riched20 control is created and positioned on top of the tab control
  • The file contents are streamed into the riched20 control

The result is a tab control with what seems at first an invisible riched20 control, though its scroll bar is visible. If I click in it, I see the caret, so the control is there. If I scroll it, the text that was out of view gets scrolled onto the screen. If I click on the scroll bar arrows, they appear. I notice that the editor doesn't fill the tab control; there's some unoccupied space at the bottom.

If I resize the window in any way all the controls are positioned and drawn correctly. There's some kind of initial painting problem going on. I tried putting the code that does the resizing properly in a separate function and calling it after opening the file, but the problem doesn't go away.

Here is the code that executes after picking a file:

  RECT tabControlRect;
GetClientRect(mWindowHandle, &tabControlRect);
if (!mTabControl) {
mTabControl = new TabControl(mWindowHandle, mInstanceHandle,
tabControlRect);
}
unsigned int tabIndex = mEditors.size();
mTabControl->addTab(tabIndex, fileName);
HWND tabControlHandle = mTabControl->getHandle();
TabCtrl_AdjustRect(tabControlHandle, FALSE, &tabControlRect);
RECT editorRect;
editorRect.left = tabControlRect.left;
editorRect.top = tabControlRect.top;
editorRect.right = tabControlRect.right - tabControlRect.left;
editorRect.bottom = tabControlRect.bottom - tabControlRect.top;
Editor* editor = new Editor(mWindowHandle, mInstanceHandle, editorRect);
editor->loadFile(filePath);
mEditors.push_back(editor);

The code that creates the tab control:

  mHandle = CreateWindowEx(NULL, WC_TABCONTROL, "", WS_CHILD | WS_VISIBLE, aRect.left, aRect.top, aRect.right, aRect.bottom, aParentWindowHandle, NULL, aInstanceHandle, NULL);

The code that creates the riched20 control:

  mHandle = CreateWindowEx(0, "RichEdit20A", "", WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE | ES_NOHIDESEL, aRect.left, aRect.top, aRect.right, aRect.bottom, aParentWindowHandle, NULL, aInstanceHandle, NULL);
if (mHandle == NULL) {
MessageBox(NULL, "RichEdit control creation failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
}
SendMessage(mHandle, EM_EXLIMITTEXT, 0, -1);
SendMessage(mHandle, EM_SETEVENTMASK, 0, (LPARAM)(DWORD)ENM_CHANGE);
HDC hdc = GetDC(NULL);
long lfHeight = -MulDiv(12, GetDeviceCaps(hdc, LOGPIXELSY), 72);
ReleaseDC(NULL, hdc);
HFONT fontHandle = CreateFont(lfHeight, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "FixedSys");
if (fontHandle) {
SendMessage(mHandle, WM_SETFONT, (WPARAM)fontHandle, MAKELPARAM(FALSE, 0));
DeleteObject(fontHandle);
}

Link to post
Share on other sites

Thanks for the response. Unfortunately, that didn't work. :(

I wasn't sure if I had to provide the handle of the control, or the parent window, so I tried both approaches. If I update the parent window, the riched20 control flashes on the screen for a split-second before being obscured as usual.

Link to post
Share on other sites

Looking though your code, I see that your tabcontrol fills the whole clientarea of it's parent. Further it seems your richedit control has the same parent as the tabcontrol. If that is all true your should make the tabcontrol parent of the richedit control.

Further there is a bug in this code:

HFONT fontHandle = CreateFont(lfHeight, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "FixedSys");
if (fontHandle) {
SendMessage(mHandle, WM_SETFONT, (WPARAM)fontHandle, MAKELPARAM(FALSE, 0));
DeleteObject(fontHandle);
}

You shouldn't delete the font until mHandle doesn't need it anymore. That is when mHandle gets another font, or when mHandle is destroyed.

Link to post
Share on other sites

What you say is true, so I've made the tab control the parent of the riched20 control. It now draws properly! Thanks a lot. :)

The code sizing my controls doesn't work anymore, though. I guess it's back to using SetPosition().

I have one concern, though. One reason I've read why others don't do this is because you won't get any messages from the child control. The tab control will get them instead. The only message I need from it is when its content have been changed.

Thanks for the bug report about the font handle; I've fixed it.

Edited by BenoitRen
Link to post
Share on other sites

I have one concern, though. One reason I've read why others don't do this is because you won't get any messages from the child control. The tab control will get them instead. The only message I need from it is when its content have been changed.

You can simply subclass the tabcontrol to get that message.

LRESULT (CALLBACK* OldWndProc)(HWND, UINT, WPARAM, LPARAM); 

LRESULT CALLBACK SubClassFunc( HWND hWnd,UINT Message, WPARAM wParam, LPARAM lParam )
{
    if ( Message == WM_CONTENTS_CHANGED )
    {
        // Whatever
    }
    return CallWindowProc( OldWndProc, hWnd, Message, wParam, lParam);
}



hWnd = CreateWindowEx(0, "RichEdit20A", ... );
// Now subclass the window that was just created.
OldWndProc = (WNDPROC)SetWindowLong( hWnd, GWL_WNDPROC, (DWORD) SubClassFunc );

Link to post
Share on other sites
  • 2 weeks later...
  • 1 month later...

I'm having a problem with this again. When I change the active tab's text, the richedit control doesn't get redrawn. I thought the solution would be to use the UpdateWindow function on the richedit control's handle, but this doesn't always work.

When my application detects that the text in the richedit control has been changed, it changes the tab text to the file name plus an asterisk. In this case calling UpdateWindow works.

When I save the current file and change the tab text to the file name without an asterisk, calling UpdateWindow doesn't work. The richedit control doesn't get redrawn.

I've looked through my code and it doesn't look like it's the result of anything I'm doing.

It's not the only redrawing problem I'm having, but it is the biggest one. **** it, this is such a pain. :(

Link to post
Share on other sites

After some more googling I found a relevant thread. I tried using InvalidateRect(), and that worked. Yay!

I'm wondering what the deal is with the menus, though. When my application launches, the Edit and Search menus are disabled. As soon as I launch a file, I enable them, but they remain gray until I force a repaint by moving or resizing the window.

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...