I've a problem with my code. I've created a class for Drag & Drop but during the dragging of the object i see a annoying flickering effect for the object that i'm dragging
void CDragDropListBox::DrawDragRect(CPoint point, CDragItem* DragItem,SIZE Size)
{
CDC* pDC = GetDC();
ScreenToClient(&point);
//Rect centered under mouse pointer
point.x -= Size.cx/2;
point.y -= Size.cy/2;
CRect rectFull(point,m_RectSize);
//Delete previous rect
ClientToScreen(&m_OldRect);
_DstWnd->ScreenToClient(&m_OldRect);
_DstWnd->InvalidateRect(m_OldRect, true);
_DstWnd->UpdateWindow();
//Draw new rect based on mouse position
DrawSelectFrame(pDC,rectFull);
DrawSingleItem(DragItem,pDC,rectFull);
m_OldRect = rectFull;
}
In my code every time i move the mouse i delete the previously drawn drag-rect and paint a new one, but the flickering is very fastidious...
There is anything i can do?
The main problem here is, that the erasing and painting is done in two steps.
And even if it is executed fast. It looks like flickering.
So don't use WM_ERASEBKGND, and use double buffering (with a memory DC) in WM_PAINT.
See CMemDC in Codeproject for a good and easy class.
I've edited my code for remove the use of UpdateWindow()
void CDragDropListBox::DrawDragRect(CPoint point, CDragItem* DragItem,SIZE Size)
{
CDC* pDC = _DstWnd->GetDC();
CDC dcMemory;
ScreenToClient(&point);
dcMemory.CreateCompatibleDC(pDC);
CDC* olddc= pDC;
CRect tmprect;
pDC->GetClipBox(&tmprect);
CBitmap tmpbmp;
tmpbmp.CreateCompatibleBitmap(pDC, tmprect.Width(), tmprect.Height());
CBitmap* OldBmp;
OldBmp = dcMemory.SelectObject(&tmpbmp);
point.x -= Size.cx/2;
point.y -= Size.cy/2;
CRect rectFull(point,m_RectSize);
ClientToScreen(&m_OldRect);
_DstWnd->ScreenToClient(&m_OldRect);
_DstWnd->InvalidateRect(m_OldRect, TRUE);
m_OldRect = rectFull;
ClientToScreen(&rectFull);
_DstWnd->ScreenToClient(&rectFull);
DrawSelectFrame(pDC,rectFull);
DrawSingleItem(DragItem,pDC,rectFull);
_DstWnd->ValidateRect(rectFull);
//_DstWnd->UpdateWindow();
olddc->BitBlt(tmprect.left, tmprect.top, tmprect.Width(), tmprect.Height(), pDC, tmprect.left, tmprect.top, SRCCOPY);
dcMemory.SelectObject(OldBmp);
}
Flickering less, but can i further improve?
Related
This image shows a scene in my current app. This appearance is undesirable. The empty GtkList is only taking half the screen. How can I make it take four fifths of the screen and the done button take up one fifth? I am using the C programming language as always and Gtk3 which I just upgraded to. I am also having trouble with fat text entries, if there is a way to adjust the thickness of widgets. Making it homogeneous makes them all the same, but how can I make it NOT homogeneous but let me decide how much of the screen each widget gets?
#include "DisplayHelp.h"
#define NOTHING
void DisplayHelp(void) {
gtk_main_quit(NOTHING);
gtk_widget_destroy(Box);
Box = gtk_vbox_new(0, 0);
GtkWidget *Button = NULL;
GtkWidget *List = gtk_list_box_new();
gtk_container_add(GTK_CONTAINER(Box), List);
gtk_container_add(GTK_CONTAINER(Window), Box);
Button = gtk_button_new_with_label("Done");
gtk_box_pack_start(GTK_BOX(Box), Button, 1, 1, FALSE);
g_signal_connect(Button, "clicked", DisplayOptions, NULL);
// I need a function to adjust the size of the button here
printf("Entering the screen: Help\n");
gtk_widget_show_all(Window);
gtk_main();
}
You can use GtkGrid, set it's vertical homogenity to TRUE and set height for each widget with respect to desired proportions:
grid = gtk_grid_new ();
gtk_grid_set_row_homogeneous (grid, TRUE);
/*l t w h*/
gtk_grid_attach (grid, top_widget, 0, 0, 1, 4);
gtk_grid_attach (grid, bot_widget, 0, 0, 1, 1);
However, it may be not the best design solution, as you are wasting space for button.
I have the HDC=hdc of a bit map, a rectangle R with logical coordinates in hdc, and the HWND=hwnd of a scroll control created by CreateWindow with SBS_HORZ. The scroll control is is the child of another window. I want to display the scroll control on the bitmap in rectangle R.
I obtained a HDC for the scroll control and used BitBlt to copy the control to the rectangle. All works well if the entire scroll control is visible in it's parent BUT if the scroll bar is obscured, I get what ever is on top of the bar. If the control is off the screen I get nothing.
This is all part of an effort to periodically save a screen image of the app in case you are wondering how the scroll bar can be obscured. I do not want to bring the scroll bar's parent to the front.
Is there anyway I can get a true image of the scroll bar in these conditions?
Or alternatively, could I somehow make a scroll bar that wasn't displayed who's contents I could copy? I do know all the parameters needed.
I found the following seems to work even if the control is obscured or off the screen. Create a DC and compatible bitmap from the control. Send the control a WM_PRINT message asking it to print itself in the DC/Bitmap. Then copy the bitmap using BitBlt.
Pretty ugly! Is there a better way?
Something like this...
HDC hdcScroll;
WINDOWPLACEMENT WP;
HDC memdc;
HBITMAP membit;
hdcScroll = GetDC (hwndScroll);
GetWindowPlacement (hwndScroll, &WP);
int Height = WP.rcNormalPosition.bottom - WP.rcNormalPosition.top;
int Width = WP.rcNormalPosition.right - WP.rcNormalPosition.left;
memdc = CreateCompatibleDC(hdcScroll); // destination DC
membit = CreateCompatibleBitmap(hdcScroll, Width, Height); // destination bitmap
HBITMAP hOldBitmap =(HBITMAP) SelectObject(memdc, membit); // add bitmap to DC
SendMessage (hwndScroll,WM_PRINT,(WPARAM) memdc, PRF_CLIENT);
BitBlt
(hdc, // destination HDC
rt_scroll.left, // dest upper left corner X
rt_scroll.top, // dest upper left corner Y
rt_scroll.right-rt_scroll.left+1, // width of dest rectangle
rt_scroll.bottom-rt_scroll.top+1, // height of dest rectangle
memdc, // source HDC
0, // source upper left corner X
0, // source upper left cornet Y
SRCCOPY
);
SelectObject(memdc, hOldBitMap);
DeleteObject (membit);
DeleteDC (memdc);
ReleaseDC (hwndScroll, hdcScroll);
Using free glut on windows 7 home ultimate with video card ati mobility radeon 5650
code snippet:
void ResizeFunction(int width, int height)
{
glViewport(0, 0, width, height);
}
void RenderFunction()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//...drawing code based on some flag, I draw a triangle or a rectangle
//the flag is toggled on pressing 't' or 'T' key
glutSwapBuffers(); //double buffering is enabled
glutPostRedisplay();
}
void KeyboardFunction(unsigned char key, int x, int y)
{
switch(key)
{
case 't':
case 'T':
{
flag = !flag;
glutPostRedisplay();
break;
}
default:
break;
}
}
problem: The triangle or the rectangle is drawn covering the entire window first time. But if I partially cover the glut window with another window (say, with some notepad window) and then uncover it, subsequently, when I toggle, the object is drawn only in the covered portion of the glut window. If I re-size the glut window, drawing works correctly as before.
Any help will be appreciated.
regards,
fs
Glut only redraws on the screen when you tell it or when it decides. That is, if you don't do anything in the window, the scene is not redrawn. Advantage of this: less cpu/gpu usage. Disadvantage: Only good for non animated applications.
If you want to constantly update the screen (which is what is done in applications with lots of animations (games for example)), you can use glutIdleFunc
http://www.opengl.org/resources/libraries/glut/spec3/node63.html
That is in the beginning of the program when you set all the functions for glut, you also write:
glutIdleFunc(RenderFunction);
This way, when glut is idle, it keeps calling your render function.
If you want to render slower than possible (for example with a fixed frame rate), you could use a timer:
void RenderFunction()
{
glutTimerFunc(YOUR_DELAY_IN_MS, RenderFunction, 0);
/* rest of code */
}
and instead of glutIdleFunc(RenderFunction);, you write
`glutTimerFunc(YOUR_DELAY_IN_MS, RenderFunction, 0);`
To simply call the render function once (you could also just write RenderFunction() once) and the function keeps setting the timer for its next run.
As a side note, I suggest using SDL instead of glut.
I'm trying to create a widget which paints directly to the windows Device Context by calling getDC() and painting an HBITMAP to it.
The widget I'm painting resides inside a scroll widget.
I've implemented the paintEvent() and it does seem to paint but immediatly after painting the widget gets painted over again with a blank gray color.
I've tried setting WA_PaintOnScreen and Qt::WA_NoSystemBackground but none of those help.
In theory this should be possible since this is basically how the GLWidget works.
What am I missing?
Found the answer here:
http://www.qtchina.net/qt4c++guiprogramming/ch20lev1sec1.html/
void GdiControl::paintEvent(QPaintEvent * /* event */)
{
RECT rect;
GetClientRect(winId(), &rect);
HDC hdc = GetDC(winId());
FillRect(hdc, &rect, HBRUSH(COLOR_WINDOW + 1));
SetTextAlign(hdc, TA_CENTER | TA_BASELINE);
TextOutW(hdc, width() / 2, height() / 2, text.utf16(), text.size());
ReleaseDC(winId(), hdc);
}
For this to work, we must also
reimplement
QPaintDevice::paintEngine() to return
a null pointer and set the
Qt::WA_PaintOnScreen attribute in the
widget's constructor.
Wee.
So I finally figured out how the iIntegral member of TVITEMEX works. The MSDN docs didn't think to mention that setting it while inserting an item has no effect, but setting it after the item is inserted works. Yay!
However, when using the TVS_HASLINES style with items of variable height, the lines are only drawn for the top part of an item with iIntegral > 1. E.g. if I set TVS_HASLINES and TVS
Here's what it looks like (can't post images WTF?)
Should I manually draw more of the lines in response to NM_CUSTOMDRAW or something?
Yes, Windows doesn't do anything with the blank space obtained from changing the height.
From the MSDN:
The tree-view control does not draw in the
extra area, which appears below the
item content, but this space can be
used by the application for drawing
when using custom draw. Applications
that are not using custom draw should
set this value to 1, as otherwise the
behavior is undefined.
Alright, problem solved.
I failed to find an easy answer, but I did work around it the hard way. It's basically just drawing the extra line segments in custom draw:
// _cd is the NMTVCUSTOMDRAW structure
// ITEMHEIGHT is the fixed height set in TreeView_SetItemHeight
// linePen is HPEN of a suitable pen to draw the lines (PS_ALTERNATE etc.)
// indent is the indentation size returned from TreeView_GetIndent
case CDDS_ITEMPREPAINT : {
// Expand line because TreeView is buggy
RECT r = _cd->nmcd.rc;
HDC hdc = _cd->nmcd.hdc;
HTREEITEM hItem = (HTREEITEM) _cd->nmcd.dwItemSpec;
if( r.bottom - r.top > ITEMHEIGHT ) {
HGDIOBJ oldPen = SelectObject( hdc, linePen );
// Draw any lines left of current item
HTREEITEM hItemScan = hItem;
for( int i = _cd->iLevel; i >= 0; --i ) {
// Line should be drawn only if node has a next sibling to connect to
if( TreeView_GetNextSibling( getHWnd(), hItemScan ) ) {
// Lines seem to start 17 pixels from left edge of control. But no idea
// where that constant comes from or if it is really constant.
int x = 17 + indent * i;
MoveToEx( hdc, x, r.top + ITEMHEIGHT, 0 );
LineTo( hdc, x, r.bottom );
}
// Do the same for the parent
hItemScan = TreeView_GetParent( getHWnd(), hItemScan );
}
SelectObject( hdc, oldPen );
}
}
The pattern from the PS_ALTERNATE brush sometimes doesn't align perfectly with line drawn by the control, but that's hardly noticeable. What's worse is that even though I have the latest common controls and all the service packs and hotfixes installed, there are still bugs in TreeView documented way back in 2005. Specifically, the TreeView doesn't update its height correctly. The only workaround I've found for that is to force some collapsing/expanding of nodes and do a few calls to InvalidateRect.
If the variable-height nodes are at the root level, though, there doesn't appear to be anything you can do. Luckily I don't need that.