2011-06-03 22 views
0

我已经创建了一个自定义控件,方法是为其注册一个新类并将其作为子实例化为顶级窗口。该控件基本上是一个列表。为了节省一些工作量,我决定使用WS_VSCROLL窗口类来添加滚动条到我的自定义控件。滚动条箭头不会重绘,而拇指曲正确重绘

我的问题是,当我调整窗口大小时,我会重新计算缩略图大小和页面大小等,然后调用SetScrollInfo,将重绘变量设置为true。这会正确重绘thumbtrack,但箭头不会重绘。因此,如果我从下面调整窗口大小,the top arrow is still good,但最下面的一个不见了。如果我调整到右侧,那么两个箭头都会改变位置and so both disappear

我似乎无法找到一种方法来获取WS_VSCROLL创建的内部滚动条控件的句柄,以便对其调用invalidate或其他东西。我真的不知道如何在这里继续。有一点要记住的是,如果我添加CS_VREDRAW | CS_HREDRAW到顶层窗口,一切都被正确绘制,所以我知道至少内部值都很好。只是那样我得到了太多的重绘和闪烁。

编辑:我发布了一些代码。我真的很想避免这种情况,因为我可能会感到羞愧,但请知道,除了我自己以外,没有人会使用它。

控件是一列类似Tweetdeck工作的推文。每条推文也是一个自定义控件,但是这种绘画很好,我在那里没有问题。列控件本身根本不响应WM_PAINT,因为它只包含处理自己绘画的Tweet控件。

这里同时为每个这些窗口类:

  • 寄存器类别顶级的是NULL和CreateWindow的类WS_OVERLAPPED | WS_CLIPCHILDREN。
  • 列的寄存器类为NULL,CreateWindow类为WS_CHILD | WS_VSCROLL。
  • tweet的注册类为NULL,CreateWindow类为WS_CHILD。

代码:

LRESULT Column::OnResize(WPARAM wParam, LPARAM lParam) // responds to WM_SIZE 
{ 
    // global height var 
    lastWidth = width; 
    lastHeight = height; 
    width = LOWORD(lParam); 
    height = HIWORD(lParam); 
    //updateScrollPageSize(); 

    SCROLLINFO si; 
    si.cbSize = sizeof(si); 
    si.fMask = SIF_ALL; 
    GetScrollInfo (hWnd, SB_VERT, &si); 

    // Resize all child tweets 
    if (lastWidth != width || 
     lastHeight != height && si.nMax - si.nPos < height) 
    { 
     // C++0x lambdas can only take in local variables?! 
     int localWidth = width; 
     int *tweetBottomPtr = &lastTweetBottom; 
     *tweetBottomPtr = 0; 
     std::for_each(tweets.begin(), tweets.end(), 
         [localWidth, tweetBottomPtr, &si](TweetBox *tweet) 
     { 
      MoveWindow(tweet->getHandle(), 
         tweet->getX(), *tweetBottomPtr - si.nPos, 
         localWidth, tweet->getHeight(), TRUE); 
      *tweetBottomPtr += tweet->getHeight(); 
     }); 
    } 

    updateScrollPageSize(); 
    UpdateWindow(hWnd); 

    return 0; 
} 

void Column::updateScrollPageSize() 
{ 
    SCROLLINFO si; 
    // Set the vertical scrolling range and page size 
    si.cbSize = sizeof(si); 
    si.fMask = SIF_ALL; 
    GetScrollInfo (hWnd, SB_VERT, &si); 

    si.fMask = SIF_PAGE | SIF_RANGE; 
    si.nMin = 0; 
    si.nMax = lastTweetBottom; 
    si.nPage = (int)((float)height/lastTweetBottom * si.nMax); 
    SetScrollInfo(hWnd, SB_VERT, &si, TRUE); 
} 
+0

您的滚动条是在子窗口还是父窗口上实现的? – johnathon 2011-06-03 02:41:37

+0

在子窗口上,我的自定义类。 – eeyore22 2011-06-03 03:17:06

+0

你用什么来画你的课,D2D,GDI,GDI +,DirectX是什么? – johnathon 2011-06-03 04:06:40

回答

0

您可以尝试将额外的WM_NCPAINT消息发送到WM_SIZE处理程序中的列。但我认为这是自动发生的。

但我觉得BrendanMcK提出的解决方案是利用默认列表框获胜。可惜这不是一个答案。

0

你的父类,而不是你的子类实现你的滚动条。这将防止重新绘制子类的消息,导致子类完全重绘它自己。不要在父类上处理wm_paint消息,只能在您的子类中处理。这将允许窗口在滚动条上进行默认处理。而且这两个窗口都需要CS_HREDRAW | CS_VREDRAW。

+0

我看不出如何在父类上实现滚动条。我的子控件没有填满整个窗口,窗口中有几个控件,所以它必须有自己的滚动条。你的意思是我应该在顶层创建一个SCROLLBAR类的控件,并从那里处理孩子的滚动?这似乎是在惹麻烦。我的孩子控制应该是自给自足的。我也没有处理父母的WM_PAINT。 – eeyore22 2011-06-03 04:21:58

+0

不,将您的实际绘图窗口托管在另一个窗口内,并将其子类化为托管控件的父窗口,但考虑到您不使用Direct 2D,此*可能不必要。 – johnathon 2011-06-03 05:03:01

+0

你在registerwindowclass上使用的样式和createwindowex是什么? – johnathon 2011-06-03 05:04:26