I am drawing ruler using the sample application given in the link.
http://www.ucancode.net/Visual_C_Source_Code/MFC-MDI-SDI-Example-create-ruler-scrollview-splitter.htm
On moving cursor they are drawing black line marker. I want to draw red color line like in microsoft paint application.
In the sample they are using below code for drawing line.
What needs to be done to draw red color line.
void CRulerView::DrawCursorPos(CPoint NewPos)
{
if (((m_rulerType == RT_HORIZONTAL) && (NewPos.x > m_DocSize.cx*m_fZoomFactor)) ||
((m_rulerType == RT_VERTICAL) && ((NewPos.y) > m_DocSize.cy*m_fZoomFactor)))
return;
CDC* pDC = GetDC();
// set the map mode right
int oldMapMode = pDC->SetMapMode(MM_TEXT);
//HBRUSH hBr=CreateSolidBrush(RGB(255,0,0));
//pDC->SelectObject(hBr);
//CBrush* pTempBrush = NULL;
// pTempBrush = (CBrush*)pDC->SelectObject(&hBr);
CRect clientRect;
GetClientRect(&clientRect);
if (m_rulerType==RT_HORIZONTAL)
{
// erase the previous position
pDC->PatBlt(m_lastPos.x, clientRect.top, 1, clientRect.bottom, DSTINVERT);
// draw the new position
m_lastPos.x = NewPos.x;
pDC->PatBlt(m_lastPos.x, clientRect.top, 1, clientRect.bottom, DSTINVERT);
}
else // (m_rulerType==RT_VERTICAL)
{
// erase the previous position
pDC->PatBlt(clientRect.left, m_lastPos.y, clientRect.right, 1, DSTINVERT);
// draw the new position
m_lastPos.y = NewPos.y;
pDC->PatBlt(clientRect.left, m_lastPos.y, clientRect.right, 1, DSTINVERT);
}
//pDC->SelectObject(&pTempBrush);
pDC->SetMapMode(oldMapMode);
ReleaseDC(pDC);
}
Related
I have two windows, one at the top, and one at the bottom (and I will be adding a third window later that will be between those two windows). I draw a horizontal line for the bottom window and then I start drawing the top window, and the bottom window gets erased!
The constructor display() is called automatically and than the function displayMessage() is called by my code.
Here is the code for display():
display::display()
{
//initialize window
initscr(); //start curses mode
cbreak(); //Disable line buffering
curs_set(0); //Don't show curser
refresh(); //Now refresh screen
//setup bottom bar
bottomBar = newwin(2, 80, 22, 0); //create new window
whline(bottomBar, '_', 80); //draw line
wrefresh(bottomBar); //refresh
//setup top bar
topBar = newwin(0, 80, 0, 0); //create new window
wattron(topBar, A_UNDERLINE); //text is to be underlined
}
Here is the code for displayMessage():
void display::displayMessage(string message)
{
//do some other necessary stuff
int length = message.length(); //get length of message
wmove(topBar, 0, 0); //move curser back to beginning
//getch();
wrefresh(topBar); //refresh
//getch();
whline(topBar, '_',80); //draw line for bottom
//getch();
wmove(topBar, 0, 40 - length/2 - 1); //move cursor to center text
wprintw(topBar,message.c_str()); //print message
wrefresh(topBar); //refresh
}
In addition here is the code snippets that call those two:
//initialize stuff
pomodoro instance;
while(true) //loop forever, or until user
{
for (int i = 0; i < 3; i++) //loop thru 4 pomodoros
{
//work
instance.Display.displayMessage("**Time to work!**");
instance.playAlarm();
//waitForUser();
//timer(config.workTime);
//break
return 0; //doing development right now
This line is a problem:
topBar = newwin(0, 80, 0, 0); //create new window
because the first parameter is zero. The manual page explains:
If either nlines or ncols is zero, they default to
LINES - begin_y and
COLS - begin_x.
So the zero-parameter makes your windows overlap (a lot).
I have refereed below article to draw a custom frame area with DWM.
Custom Window Frame Using DWM
After removing the standard frame, non client area is not exist in the frame.
void CMainFrame::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
int nTHight = 30; /*The title bar height*/
RECT * rc;
RECT aRect;
RECT bRect;
RECT bcRect;
if(bCalcValidRects == TRUE)
{
CopyRect(&aRect,&lpncsp->rgrc[1]);
CopyRect(&bRect,&lpncsp->rgrc[0]);
bcRect.left = bRect.left;
bcRect.top = bRect.top - nTHight;
bcRect.right = bRect.right;
bcRect.bottom = bRect.bottom;
CopyRect(&lpncsp->rgrc[0],&bcRect);
CopyRect(&lpncsp->rgrc[1],&bRect);
CopyRect(&lpncsp->rgrc[2],&aRect);
}
else
{
rc = (RECT *)lpncsp;
rc->left = rc->left;
rc->top = rc->top - nTHight;
rc->right = rc->right;
rc->bottom = rc->bottom;
}
CFrameWnd::OnNcCalcSize(bCalcValidRects, lpncsp);
}
Because the entire window is client region, I have to adjust the UI control placement for the frame, but I don't know how to handle this problem.
For example, below red rectangle (all UI component) should be shifted into the original coordinate of the client area before removing the non client part.
CWnd::GetWindowRect gives you the rectangle of the window on screen. The dimensions of the caption, border, and scroll bars, if present, are included.
CWnd::GetClientRect gives you the client rectangel of the window. The left and top members will be 0. The right and bottom members will contain the width and height of the window.
CWnd::ScreenToClientand CWnd::ClientToScreen calculate a point or rectangle from the client area to screen coordinates and back to screen.
AdjustWindowRect calculates the required window rectangle, based on the client rectangle of the window.
Here is afunction which calcualtes the margins of a window:
void CalculateWndMargin( const CWnd &wnd, int &leftM, int &rightM , int &topM, int &bottomM )
{
CRect wndRect;
wnd.GetWindowRect( wndRect );
CRect screenRect;
wnd.GetClientRect( screenRect );
wnd.ClientToScreen( screenRect );
leftM = screenRect.left - wndRect.left;
rightM = wndRect.right - screenRect.right;
topM = screenRect.top - wndRect.top;
bottomM = wndRect.bottom - screenRect.bottom;
}
I modified my dialog to a polygon region dialog. Then i am trying to frame/draw the border.Using device context the CRgn::FrameRgn, i am bale to draw the border around the dialog. But i want to achieve this using Gdi+. I did as below, but the border is appearing only on left and top of the dialog.
Can someone please help on this.
CPoint vertex[4];
BOOL CPolygonDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
ModifyStyle(WS_CAPTION,0);
ModifyStyle(WS_BORDER,0);
CRect rect(400,200,900,700);
CRect wr = rect;
AdjustWindowRect( wr, 0, FALSE );
MoveWindow(wr);
GetClientRect( rect );
CRect csr = rect;
ClientToScreen( csr );
vertex[0] = CPoint(rect.left,rect.top);
vertex[1] = CPoint(rect.right,rect.top);
vertex[2] = CPoint(rect.right,rect.bottom);
vertex[3] = CPoint(rect.left,rect.bottom);
m_rgnShape.CreatePolygonRgn( vertex, 4, ALTERNATE );
m_rgnShape.OffsetRgn( CPoint( csr.TopLeft() - wr.TopLeft() ) );
SetWindowRgn( (HRGN)m_rgnShape.Detach(), TRUE );
m_rgnShape.CreatePolygonRgn( vertex, 4, ALTERNATE );
return TRUE; // return TRUE unless you set the focus to a control
}
void CPolygonDlg::OnPaint()
{
Graphics graphics(dc.m_hDC);
CRect rect;
GetClientRect(rect);
GraphicsPath gp;
Point point[4];
point[0] = Point(rect.left,rect.top);
point[1] = Point(rect.right,rect.top);
point[2] = Point(rect.right,rect.bottom);
point[3] = Point(rect.left,rect.bottom);
gp.AddPolygon(point,4);
Pen pen(Color(255, 255, 0, 0));
graphics.DrawPath(&pen, &gp);
}
Thanks
When you call GetClientRect(), it returns the size of the client area of the window - the part you can easily draw on, and the part that is controlled by the device context when you do CPaintDC dc(this); in your OnPaint() method.
The problem you are facing is that your dialog window has a border and you need to handle WM_NCPAINT in order to draw on border area.
If console aplication starts and system creates console window for it, but sometimes this window is created in such coordinates that some of it's contents slide out of right screen edge. Then the user must use mouse to show everything.
How to cope with that ?
What functions use to detect upper right corner coordinates of console window ?
Then I will be able to check if it is outside the screen and move the window just the distance that is needed.
What function use to move window ?
Or maybe there is all in one solution to prevent window from moving outside the screen ?
Here's a fully multi-monitor aware and taskbar aware implementation that does what you describe.
#include <Windows.h>
int main()
{
ClampConsoleToScreen();
return 0;
}
void ClampConsoleToScreen()
{
HWND window = GetConsoleWindow();
RECT windowRect;
GetWindowRect(window, &windowRect);
HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY);
MONITORINFO mi;
memset(&mi, 0, sizeof(mi));
mi.cbSize = sizeof(mi);
GetMonitorInfo(monitor, &mi);
int adj, any;
adj = 0;
any = 0;
if (windowRect.right > mi.rcWork.right)
{
// Get negative adjustment value to move it left onto screen
adj = mi.rcWork.right - windowRect.right;
}
if (windowRect.left < mi.rcWork.left)
{
// Get positive adjustment value to move it right onto screen
adj = mi.rcWork.left - windowRect.left;
}
windowRect.left += adj;
windowRect.right += adj;
any |= adj;
adj = 0;
if (windowRect.bottom > mi.rcWork.bottom)
{
// Get negative adjustment value to move it up onto screen
adj = mi.rcWork.bottom - windowRect.bottom;
}
if (windowRect.top < mi.rcWork.top)
{
// Get positive adjustment value to move it down onto screen
adj = mi.rcWork.top - windowRect.top;
}
windowRect.top += adj;
windowRect.bottom += adj;
any |= adj;
if (any)
{
MoveWindow(window,
windowRect.left,
windowRect.top,
windowRect.right - windowRect.left,
windowRect.bottom - windowRect.top, TRUE);
}
}
I'm using a CListCtrl/CListView report view (LVS_REPORT) in virtual mode (LVS_OWNERDATA) with LVS_EX_DOUBLEBUFFER enabled and I encounter ugly flickering. Double buffer have a real effect but it doesn't stop all flickering (without it very slow).
I'm not looking for switching to other controls that would require a high amount of rework (like ObjectListView)
How does the flickering behaves:
on column resize - the background is first clean using lightgray and after this is displayed the text (background is white)
on mouse scroll (animated) - for a very short time there is lightgray-bar displayed in the area where new lines are to be displayed.
It looks like it does clean the background using the default window background color (lightgray) for the area where it has to redraw.
How do I solve the flickering problem?
Try to do the following:
- Set Clip Children and Clip Sibling for paremt dialog of List Control.
- Make dirived from CListCtrl class. In this class overwrite OnEraseBkgnd. In the OnEraseBkgnd fill with background color area around of visible items of the list.
The OnEraseBkgnd can look like:
BOOL CListCtrlEx::OnEraseBkgnd(CDC* pDC)
{
CBrush br;
CRect rcCli;
CRect rcItemsRect(0, 0, 0, 0);
int nHeadHeight = 0;
int nItems = GetItemCount();
GetClientRect(&rcCli);
CHeaderCtrl* pHeadCtrl = GetHeaderCtrl();
if (pHeadCtrl)
{
CRect rcHead;
pHeadCtrl->GetWindowRect(&rcHead);
nHeadHeight = rcHead.Height();
}
rcCli.top += nHeadHeight;
if (nItems > 0)
{
CPoint ptItem;
CRect rcItem;
GetItemRect(nItems - 1, &rcItem, LVIR_BOUNDS);
GetItemPosition(nItems - 1, &ptItem);
rcItemsRect.top = rcCli.top;
rcItemsRect.left = ptItem.x;
rcItemsRect.right = rcItem.right;
rcItemsRect.bottom = rcItem.bottom;
if (GetExtendedStyle() & LVS_EX_CHECKBOXES)
rcItemsRect.left -= GetSystemMetrics(SM_CXEDGE) + 16;
}
br.CreateSolidBrush(GetBkColor());
if (rcItemsRect.IsRectEmpty())
pDC->FillRect(rcCli, &br);
else
{
if (rcItemsRect.left > rcCli.left) // fill left rectangle
pDC->FillRect(
CRect(0, rcCli.top, rcItemsRect.left, rcCli.bottom), &br);
if (rcItemsRect.bottom < rcCli.bottom) // fill bottom rectangle
pDC->FillRect(
CRect(0, rcItemsRect.bottom, rcCli.right, rcCli.bottom), &br);
if (rcItemsRect.right < rcCli.right) // fill right rectangle
pDC->FillRect(
CRect(rcItemsRect.right, rcCli.top, rcCli.right, rcCli.bottom), &br);
}
return TRUE;
}
I know only way to have flicker free is using double buffering or MemDC.
have found this article: Flicker-free-drawing-of-any-control
This article explains it well how to quickly perform Non Flickering drawing on your CListCtrl.
And it works excellent.
PS: VS 2005 doesn't have CMemDC class you will need to implement it your self, or use the following code:
//
// CMemDC.h header file
//
#pragma once
class CMemDC
{
public:
CMemDC(CDC& dc, CWnd* pWnd);
CMemDC(CDC& dc, const CRect& rect);
virtual ~CMemDC();
CDC& GetDC() { return m_bMemDC ? m_dcMem : m_dc; }
BOOL IsMemDC() const { return m_bMemDC; }
BOOL IsVistaDC() const { return m_hBufferedPaint != NULL; }
void EraseBkClip();
protected:
CDC& m_dc;
BOOL m_bMemDC;
HANDLE m_hBufferedPaint;
CDC m_dcMem;
CBitmap m_bmp;
CBitmap* m_pOldBmp;
CRect m_rect;
};
//
// CMemDC.cpp source file
//
#include "CMemDC.h"
CMemDC::CMemDC(CDC& dc, CWnd* pWnd) :
m_dc(dc), m_bMemDC(FALSE), m_hBufferedPaint(NULL), m_pOldBmp(NULL)
{
ASSERT_VALID(pWnd);
pWnd->GetClientRect(m_rect);
m_rect.right += pWnd->GetScrollPos(SB_HORZ);
m_rect.bottom += pWnd->GetScrollPos(SB_VERT);
if (m_dcMem.CreateCompatibleDC(&m_dc) &&
m_bmp.CreateCompatibleBitmap(&m_dc, m_rect.Width(), m_rect.Height()))
{
m_bMemDC = TRUE;
m_pOldBmp = m_dcMem.SelectObject(&m_bmp);
}
}
CMemDC::CMemDC(CDC& dc, const CRect& rect) :
m_dc(dc), m_bMemDC(FALSE), m_hBufferedPaint(NULL), m_pOldBmp(NULL), m_rect(rect)
{
ASSERT(!m_rect.IsRectEmpty());
if (m_dcMem.CreateCompatibleDC(&m_dc) &&
m_bmp.CreateCompatibleBitmap(&m_dc, m_rect.Width(), m_rect.Height()))
{
m_bMemDC = TRUE;
m_pOldBmp = m_dcMem.SelectObject(&m_bmp);
}
}
CMemDC::~CMemDC()
{
if (m_bMemDC)
{
CRect rectClip;
int nClipType = m_dc.GetClipBox(rectClip);
if (nClipType != NULLREGION)
{
if (nClipType != SIMPLEREGION)
{
rectClip = m_rect;
}
m_dc.BitBlt(rectClip.left, rectClip.top, rectClip.Width(), rectClip.Height(), &m_dcMem, rectClip.left, rectClip.top, SRCCOPY);
}
m_dcMem.SelectObject(m_pOldBmp);
}
}
void CMemDC::EraseBkClip()
{
CRect clip;
m_dcMem.GetClipBox(&clip);
m_dcMem.FillSolidRect(clip, GetSysColor(COLOR_WINDOW));
}
There is an ultra simple way I found that worked for me:
Turn off redraw with m_List1.SetRedraw(false)
Reset contents with m_List1.ResetContents()
Add new strings in loop with m_List1.AddString()
Then finalize by turning back on redraw and a m_List1.UpdateWindow().