I am working with SDI app to redraw graph and update data by using timer in View file. Even though I use ON_WM_ERASEBKGND to eliminate flickering, but it still happen. And below are my code that I tried to implement. Anyone has any ideas to eliminate flickering?
Here are my MSG_MAP
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_WM_TIMER()
BOOL CVCDSOView::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
return TRUE;
return CView::OnEraseBkgnd(pDC);
}
void CVCDSOView::OnInitialUpdate()
{
CView::OnInitialUpdate();
CRect Rect;
GetClientRect(&Rect);
CRect m_rcDraw = Rect;
// set timer with 200ms
SetTimer(ID_LABEL_COMPANY,200,NULL);
labelCompany.Create(_T("Company"), WS_CHILD | WS_VISIBLE,
CRect(LEFT_SIDE, TOP_SIDE, RIGHT_SIDE+50, BOTTOM_SIDE), this, ID_LABEL_COMPANY);
textboxCompany.Create(WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_NOHIDESEL,
CRect(LEFT_SIDE, TOP_SIDE+VERTICAL_OFFSET, RIGHT_SIDE+50, BOTTOM_SIDE+VERTICAL_OFFSET), this, ID_EDITTEXT_COMPANY);
}
// CVCDSOView message handlers
void CVCDSOView::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
CRect Rect;
GetClientRect(&Rect);
CDC dcMem;
CBitmap bmpMem;
dcMem.CreateCompatibleDC(&dc);
bmpMem.CreateCompatibleBitmap(&dc,Rect.Width()- GRID_LEFT,Rect.Height()-35);
dcMem.SelectObject(&bmpMem);
dcMem.FillSolidRect(Rect, RGB(255,255,255));
CRect m_rcDraw = Rect;
m_rcDraw.DeflateRect(GRID_LEFT,GRID_TOP,GRID_RIGHT,GRID_BOTTOM);
DrawGrid(&dcMem,m_rcDraw);
dc.BitBlt(0,0,Rect.Width(),Rect.Height(),&dcMem,0,0,SRCCOPY);
dcMem.DeleteDC();
DeleteObject(bmpMem);
// Do not call CView::OnPaint() for painting messages
}
void CVCDSOView::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
//
if(nIDEvent==ID_LABEL_COMPANY)
{
CollectData();
Invalidate();
CView::OnTimer(nIDEvent);
}
}
Any idea would be great appreciate.
You have child controls which can cause flicker when their background is painted. You want to exclude the child controls from paint area by adding WS_CLIPCHILDREN flag to the view class:
BOOL CVCDSOView::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style |= WS_CLIPCHILDREN;
return CView::PreCreateWindow(cs);
}
Unrelated to flickering issue:
Don't subtract anything for main rectangle. You should change the bitmap to
bmpMem.CreateCompatibleBitmap(&dc, Rect.Width(), Rect.Height());
You don't need dcMem.DeleteDC() and DeleteObject(bmpMem) MFC will automatically delete these objects.
Note that MFC will not automatically de-select objects. This usually doesn't matter because Windows will do the necessary cleanup, as is done in this example. But for completeness sake add the following:
CBitmap* oldbitmap = (CBitmap*)dcMem.SelectObject(&bmpMem);
...
dc.BitBlt(0,0,Rect.Width(),Rect.Height(),&dcMem,0,0,SRCCOPY);
dcMem.SelectObject(oldbitmap);
In OnEraseBkgnd you should return FALSE.
All drawing in OnPaint should better be done with CMemDC class, because drawing straight on the screen will most likely cause flickering as well:
CMemDC memDC(*pDC, this);
CDC& rDC = memDC.GetDC();
rDC.ActualDrawing`...
Related
I've got a "default looking" dialog box like the following:
And I'm attempting to modify the tabs and insert a RichEditCtrl in the first tab.
InitCommonControlsEx;
CWnd* pTab = GetDlgItem(IDC_TAB1);
if (pTab) {
CRect rect;
m_TabCtrl = (CTabCtrl*)pTab;
m_TabCtrl->GetClientRect(&rect);
m_TabCtrl->InsertItem(0, "Stats");
m_TabCtrl->InsertItem(1, "Settings");
BOOL getRect = m_TabCtrl->GetItemRect(0, &rect);
if (!m_richEditCtrl.Create(WS_VISIBLE | ES_READONLY | ES_MULTILINE | ES_AUTOHSCROLL | WS_HSCROLL | ES_AUTOVSCROLL | WS_VSCROLL, rect, m_TabCtrl, 0))
return FALSE;
m_font.CreateFont(-11, 0, 0, 0, FW_REGULAR, 0, 0, 0, BALTIC_CHARSET, 0, 0, 0, 0, "Courier New");
m_richEditCtrl.SetFont(&m_font);
}
The sample I'm modifying previously had only used the RichTextCtrl and "created" it inside of a "placeholder" text box. It worked great, but I wanted to shove that RichTextCtrl into a tab, and create another tab to display some data. The problem is that I now just get 2 blank tabs. I know that the parent dialog settings "Clip Children" and "Clip Siblings" may matter, but I'm not sure which if I need, if either. I also know that my RichEditCtrl still exists because I'm still sending data to it, but it's certainly not displaying.
This piece of my program isn't even really that urgent, and I am just trying to get this to work on principal at this point...
Tab Controls create the illusion, that the dividers and the display area were part of the same control. That's not the case. The tab control is really just the labels, plus the placeholder display area. Bringing the display area's contents to live is the responsibility of the application.
In general, the following steps are required to implement a fully functional tab control:
Create the tab control plus labels.
Create the display area's child controls. It is common to place the controls comprising a single "page" in a dialog.
Subscribe to the TCN_SELCHANGE message, and dynamically update the visibility of the controls, i.e. hide all controls that aren't part of the current "page" and show all controls that are. Placing all controls for a "page" inside a dialog makes this easier by only requiring to toggle the visibility of the dialogs.
This is a rough overview of how tab controls work. Given your code, there are some things you need to change. Specifically, the following need to be taken care of:
The tab control referenced by IDC_TAB1 needs to have the WS_CLIPCHILDREN style, so that the display area doesn't cover the child controls.
m_richEditCtrl needs to be created with the WS_CHILD style.
Calculate the size of the display area using CTabCtrl::AdjustRect and use that to size the m_richEditCtrl to fill the entire display area (if that is what you want).
With those changes you should see a tab control whose display area is filled by a Rich Edit control. Switching between tabs doesn't change the contents of the display area just yet. That's something you'll need to implement as required by your application.
The following code sample is based on a wizard-generated dialog-based application named MfcTabCtrl. The generated dialog resource (IDD_MFCTABCTRL_DIALOG) had all content removed, leaving just a blank dialog template.
Likewise, the main dialog implementation had most of its functionality stripped, leaving just the vital parts. This is the MfcTabCtrlDlg.h header:
#pragma once
#include "afxdialogex.h"
// Control identifiers
UINT constexpr IDC_TAB{ 100 };
UINT constexpr IDC_RICH_EDIT{ 101 };
class CMfcTabCtrlDlg : public CDialogEx
{
public:
CMfcTabCtrlDlg(CWnd* pParent = nullptr);
protected:
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnTabChanged(NMHDR* pNMHDR, LRESULT* pResult);
// Convenience implementation to calculate the display area
RECT GetDisplayArea();
virtual BOOL OnInitDialog();
DECLARE_MESSAGE_MAP()
private:
CTabCtrl m_TabCtrl{};
CRichEditCtrl m_richEditCtrl{};
};
The implementation file MfcTabCtrlDlg.cpp isn't very extensive either:
#include "MfcTabCtrlDlg.h"
CMfcTabCtrlDlg::CMfcTabCtrlDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_MFCTABCTRL_DIALOG, pParent)
{
}
void CMfcTabCtrlDlg::OnSize(UINT nType, int cx, int cy)
{
CDialogEx::OnSize(nType, cx, cy);
// Resize tab control only after it has been created
if (IsWindow(m_TabCtrl)) {
m_TabCtrl.MoveWindow(0, 0, cx, cy);
// Determine display area
auto const disp_area{GetDisplayArea()};
// Resize child control(s) to cover entire display area
if (!IsRectEmpty(&disp_area) && IsWindow(m_richEditCtrl)) {
m_richEditCtrl.MoveWindow(&disp_area);
}
};
}
void CMfcTabCtrlDlg::OnTabChanged(NMHDR* /*pNMHDR*/, LRESULT* pResult)
{
auto const cur_sel{ m_TabCtrl.GetCurSel() };
switch (cur_sel) {
// First tab selected
case 0:
m_richEditCtrl.ShowWindow(SW_SHOW);
break;
// Second tab selected
case 1:
m_richEditCtrl.ShowWindow(SW_HIDE);
break;
}
// Allow other subscribers to handle this message
*pResult = FALSE;
}
// Returns the display area in client coordinates relative to the dialog.
// Returns an empty rectangle on failure.
RECT CMfcTabCtrlDlg::GetDisplayArea()
{
RECT disp_area{};
if (IsWindow(m_TabCtrl)) {
m_TabCtrl.GetWindowRect(&disp_area);
m_TabCtrl.AdjustRect(FALSE, &disp_area);
this->ScreenToClient(&disp_area);
}
return disp_area;
}
// The message map registers only required messages
BEGIN_MESSAGE_MAP(CMfcTabCtrlDlg, CDialogEx)
ON_WM_SIZE()
ON_NOTIFY(TCN_SELCHANGE, IDC_TAB, &CMfcTabCtrlDlg::OnTabChanged)
END_MESSAGE_MAP()
BOOL CMfcTabCtrlDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// Set up tab control to cover entire client area
RECT client{};
GetClientRect(&client);
m_TabCtrl.Create(WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN, client, this, IDC_TAB);
m_TabCtrl.InsertItem(0, L"Stats");
m_TabCtrl.InsertItem(1, L"Settings");
// Set up rich edit control.
// The WS_BORDER style is set strictly to make it visible.
auto const disp_area{ GetDisplayArea() };
m_richEditCtrl.Create(WS_BORDER | WS_VISIBLE | WS_CHILD,
disp_area, &m_TabCtrl, IDC_RICH_EDIT);
return TRUE; // Let the system manage focus for this dialog
}
The result is a dialog holding a tab control with two labels. Visibility of the contained rich edit control is toggled in the TCN_SELCHANGE notification handler, showing it only when the first tab is selected. A more complex GUI would update the visibility of all controls based on the currently selected tab here as well.
Note that the controls inside the tab control's display area are never destroyed during the dialog's life time. This is usually desirable to persist user data even when switching between tabs. If necessary it is also possible to destroy and (re-)create some or all of the child controls when switching tabs.
Output is show in picture
I am using one CStatic control with variable as "m_background" and ID as IDC_background. In this control, the video has been run on the click of the button. and there is second control Edit Control with variable as "m_edit" and ID as IDC_edit.This Edit Box is placed over static control. I want to show the text written in Edit Control on video while we play video on click of the button with transparent background color of EDit Control.
But the problem is grey/white background has appeared for m_edit control while we play video. I want to show the text on the video with transparent background of the "m_edit" control while we play the video.
BOOL CtestcodeDlg::OnInitDialog()//To set up the video in background and text above the video
{
m_background.ModifyStyle(0, WS_CLIPSIBLINGS);
m_edit.SetWindowPos(&CWnd::wndTop, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE|WS_EX_TRANSPARENT);
return TRUE; // return TRUE unless you set the focus to a control
}
HBRUSH CtestcodeDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) //To transparent the background of Edit box
{
HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
HBRUSH m_default=CreateSolidBrush(RGB(0,0, 0));
if(pWnd->GetDlgCtrlID() == IDC_edit)
{
pDC->SetTextColor(RGB(255,0,0));
pDC->SetBkColor(TRANSPARENT);
pDC->SetBkMode(TRANSPARENT);
}
return hbr;
}
void CtestcodeDlg::OnBnClickedButton1()////To run the video
{
my_instance = libvlc_new(0, NULL);
my_media_file = libvlc_media_new_location(my_instance,
"rtsp://BigBuckBunny_115k.mov");
my_player = libvlc_media_player_new_from_media(my_media_file);
my_event_manager = libvlc_media_player_event_manager(my_player);
libvlc_media_player_play(my_player);
libvlc_audio_set_track(my_player ,-1);
libvlc_media_player_set_hwnd(my_player, m_background);
Sleep(1000);
_beginthread(test, 0, NULL);
libvlc_audio_set_track(my_player ,-1);
}
Try using SetLayeredWindowAttributes function, with the crKey of your bk color.
Also, i think pDC->SetBkColor(TRANSPARENT); in your code is a mistake, it sets bk color to black. Try to run without this call.
I created a MFC application.Sometimes the controls(Button,Label etc) in the Dialog goes invisible at run time.The Dialog form remains.This is a random issue.The screenshots of the dialog in normal time and when goes blank are attached.Can anyone help me to find the solution for this ?
http://i.stack.imgur.com/KTDGV.png
http://i.stack.imgur.com/3PqUb.png
for displaying/hiding the Dialog i used the following code
void CVideoConverter::PopUpDlg(BOOL bValue)
{
try
{
if(bValue) // show
{
CVideoConverterApp::m_pCVideoConverterDlg->ShowWindow(SW_SHOWNORMAL);
CVideoConverterApp::m_pCVideoConverterDlg->UpdateWindow();
}
else
{// hide
CVideoConverterApp::m_pCVideoConverterDlg->ShowWindow(SW_MINIMIZE);
}
}
catch(...)
{}
}
The following code was used to position the dialog to bottom right corner of the window.This is called before the PopupDlg()
void CVideoConverter::SetWindowToBottomRightCorner()
{
try
{
CRect rcScreen;
SystemParametersInfo(SPI_GETWORKAREA, 0, (void *) &rcScreen, 0);
CRect rcWindow;
GetWindowRect(&rcWindow);
MoveWindow(rcScreen.right - rcWindow.Width(), rcScreen.bottom - rcWindow.Height(), rcWindow.Width(), rcWindow.Height(), TRUE);
}
catch(...)
{}
}
I am trying to add to CSliderCtrl in CStatusBar. For this
- Created CSliderCtrl in CMainFrame class
- In CMainFrame::OnCreate() added code for creating statusbar and slider bar control as
bStatus = m_ZoomSlider.Create(
WS_CHILD | WS_VISIBLE,
CRect(0, 0, 100, 30),
&m_StatusBar,
56666);
Things are working fine.
Now I want this slider to be on the right side of the status bar. For this I've added a INDICATOR in the status bar and I am trying to get the rect of this indicator and placing the slider over that rect.
CRect rectSlider;
m_StatusBar.GetItemRect(1, &rectSlider);
bStatus = m_ZoomSlider.Create(
WS_CHILD | WS_VISIBLE,
rectSlider,
&m_StatusBar,
56666);
Here the rectSlider is having negative value, causing the slider to be invisible.
I need to know Is this the correct way for doing this. Any suggestion for advice will be very helpful.
I am using Visual Studio 2005.
You should be using GetRect rather than GetItemRect, I think
The slider control cannot be displayed because its Z-order is not correct. So override on resize to reposition the slider properly. &CWnd::wndTop means placing the window at the top of the Z-order
Firstly, define CSliderCtrl *m_pZoomSlider in MainFrame.h
The following code used the lazy initialization pattern: initialize when required, free the allocated memory when frame is being destroyed.
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
...
ON_WM_SIZE()
END_MESSAGE_MAP()
void CMainFrame::SetSliderPosition(int pos)
{
if (!m_pZoomSlider) {
CRect rectSlider;
m_wndStatusBar.GetItemRect(1, &rectSlider);
rectSlider.DeflateRect(1, 1); // 1 pixel border...
m_pZoomSlider = new CSliderCtrl();
m_pZoomSlider->Create(WS_CHILD | WS_VISIBLE, rectSlider, &m_wndStatusBar, ID_INDICATOR_SCALE_SLIDER);
m_pZoomSlider->SetRange(1, 100);
}
RECT rc;
m_wndStatusBar.GetItemRect(pos, &rc);
// Reposition the slider control correctly!
m_pZoomSlider->SetWindowPos(&CWnd::wndTop, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, 0);
}
void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
CFrameWnd::OnSize(nType, cx, cy);
SetSliderPosition(1); //index of indicator of status bar
}
BOOL CMainFrame::DestroyWindow()
{
if (m_pZoomSlider) {
m_pZoomSlider->DestroyWindow();
delete m_pZoomSlider;
}
return CFrameWnd::DestroyWindow();
}
I know it can be done with OnCtlColor(), but it changes colors when the form is being loaded and the static texts are to be drawn, I want to do it after form is loaded, with a timer maybe, I searched for a solution but I didn't find a clear one, this is what I wrote:
void CTabFive::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
CWnd* pWnd = this->GetDlgItem(IDC_Chromosome1);
CDC* dc = pWnd->GetDC();
dc->SetBkColor(RGB(200,0,0));
pWnd->Invalidate();
pWnd->UpdateWindow();
Invalidate();
UpdateWindow();
//flag = true;
}
No timer is needed. Here I have a bool m_coloured member of the class initialized to false, and toggled in the button press. The OnCtlColor will draw in red or in the system colour depending on the value of m_coloured. Works nicely.
HBRUSH Cmfcvs2010Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
if (nCtlColor == CTLCOLOR_STATIC && pWnd->GetDlgCtrlID() == IDC_LABEL)
{
DWORD d = GetSysColor(COLOR_BTNFACE);
COLORREF normal = RGB(GetRValue(d), GetGValue(d), GetBValue(d));
COLORREF red = RGB(255, 0, 0);
pDC->SetBkColor(m_coloured ? red : normal);
}
return hbr;
}
void Cmfcvs2010Dlg::OnBnClickedButton1()
{
m_coloured = !m_coloured;
Invalidate();
}