解决绘图闪烁问题--双缓冲技术

一、缓冲技术原理:为了解决窗口刷新频率过快所带来的闪烁问题,利用双缓冲技术进行绘图。所谓双缓冲技术,就是将资源加载到内存,然后复制内存数据到设备DC(这个比较快),避免了直接在设备DC上绘图(这个比较慢)。

二、列子示例:

  1 void CDlgDrawSignature::OnPaint()
  2 {
  3     CPaintDC dc(this); // device context for painting
  4     // TODO: 在此处添加消息处理程序代码
  5     // 不为绘图消息调用 CDialogEx::OnPaint()
  6 
  7     CRect ctrlRect;
  8     this->GetClientRect(&ctrlRect);//获取尺寸
  9 
 10     
 11     CDC dcMemory;
 12     dcMemory.CreateCompatibleDC(&dc);//创建内存DC
 13 
 14 
 15     CBitmap *pOldMapMemory;
 16     CBitmap mapMemory;
 17     mapMemory.CreateCompatibleBitmap(&dc, ctrlRect.Width(), ctrlRect.Height());//创建控件DC的兼容位图。其实就是与控件DC大小相同的一块区域
 18     pOldMapMemory = dcMemory.SelectObject(&mapMemory);//加载兼容位图,只有制定了“桌布”尺寸之后,你才能在内存DC上面绘图
 19 
 20     dcMemory.FillRect(&ctrlRect,&CBrush(RGB(255,255,255)));    
 21     DrawButton(&dcMemory);//在内存DC上绘图
 22 
 23     dc.BitBlt(0, 0, ctrlRect.Width(), ctrlRect.Height(), &dcMemory, 0, 0, SRCCOPY);//将内存DC上的内容复制到控件DC上
 24     dcMemory.SelectObject(pOldMapMemory);//还原原来的内存DC
 25     ::DeleteObject(mapMemory);//删除兼容位图资源
 26     ::DeleteDC(dcMemory);//删除内存DC
 27     ReleaseDC(&dc);//释放控件DC
 28 }
 29 
 30 void CDlgDrawSignature::DrawButton(CDC* pDc)
 31 {
 32     //画黑色标题栏
 33     CBrush brush(RGB(0,0,0));
 34     pDc->FillRect(&m_rcHit,&brush);
 35 
 36     CPoint   point;
 37     GetCursorPos(&point);
 38     ScreenToClient(&point);
 39     if (m_rcClose.PtInRect(point))
 40     {
 41         //红色关闭按钮背景
 42         CBrush brushRed(RGB(255,0,0));
 43         pDc->FillRect(&m_rcClose,&brushRed);
 44     }
 45 
 46     //画白色关闭的X
 47     CPen pen(PS_SOLID,2,RGB(255,255,255));
 48     CPen* penOld = pDc->SelectObject(&pen);
 49     pDc->MoveTo(CPoint(m_rcClose.left+4,m_rcClose.top+4));
 50     pDc->LineTo(CPoint(m_rcClose.right-4,m_rcClose.bottom-4));
 51     pDc->MoveTo(CPoint(m_rcClose.right-4,m_rcClose.top+4));
 52     pDc->LineTo(CPoint(m_rcClose.left+4,m_rcClose.bottom-4));
 53     pDc->SelectObject(penOld);
 54 
 55     //绘画保存按钮
 56     CPen penBorder(PS_SOLID,1,RGB(0,0,0));
 57     penOld = pDc->SelectObject(&penBorder);
 58     pDc->Rectangle(&m_rcSave);
 59     pDc->SelectObject(penOld);
 60     if (m_rcSave.PtInRect(point))
 61     {
 62         CBrush brushBlue(RGB(65,105,255));
 63         pDc->FillRect(&m_rcSave,&brushBlue);
 64         m_bSave = TRUE;
 65     }
 66     else
 67     {
 68         m_bSave = FALSE;
 69     }
 70     //设置字体  
 71     CFont font;  
 72     font.CreateFont( 18,                    //   nHeight     
 73         0,                                  //   nWidth     
 74         0,                                  //   nEscapement   
 75         0,                                  //   nOrientation     
 76         FW_NORMAL,                          //   nWeight     
 77         FALSE,                              //   bItalic     
 78         FALSE,                              //   bUnderline     
 79         0,                                  //   cStrikeOut     
 80         ANSI_CHARSET,                       //   nCharSet     
 81         OUT_DEFAULT_PRECIS,                 //   nOutPrecision     
 82         CLIP_DEFAULT_PRECIS,                //   nClipPrecision     
 83         DEFAULT_QUALITY,                    //   nQuality     
 84         DEFAULT_PITCH   |   FF_SWISS,       //   nPitchAndFamily       
 85         _T("宋体"));  
 86 
 87     CFont* pFont = pDc->SelectObject(&font);  
 88     pDc->SetBkMode(TRANSPARENT);
 89     pDc->DrawText("保  存",&m_rcSave,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
 90 
 91 
 92     //绘画清除按钮
 93     penOld = pDc->SelectObject(&penBorder);
 94     pDc->Rectangle(&m_rcClear);
 95     pDc->SelectObject(penOld);
 96     if (m_rcClear.PtInRect(point))
 97     {
 98         CBrush brushBlue1(RGB(65,105,255));
 99         pDc->FillRect(&m_rcClear,&brushBlue1);
100         m_bClear = TRUE;
101     }
102     else
103     {
104         m_bClear = FALSE;
105     }
106 
107     pDc->DrawText("清  除",&m_rcClear,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
108 
109     pDc->SelectObject(pFont);
110 }

 

转载于:https://www.cnblogs.com/jgliuhui1988/p/8057437.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Qt C++ 中使用双缓冲技术进行绘图,可以按照以下步骤进行操作: 1. 创建一个自定义的 QWidget 子类,例如 MyPaintWidget,用于绘制图形。 ```cpp class MyPaintWidget : public QWidget { Q_OBJECT public: explicit MyPaintWidget(QWidget *parent = nullptr); protected: void paintEvent(QPaintEvent *event) override; private: QImage buffer; // 双缓冲区 }; MyPaintWidget::MyPaintWidget(QWidget *parent) : QWidget(parent) { // 设置窗口属性,启用双缓冲绘制 setAttribute(Qt::WA_PaintOnScreen); setAttribute(Qt::WA_NoSystemBackground); } void MyPaintWidget::paintEvent(QPaintEvent *event) { // 创建绘图对象,并将其绑定到双缓冲区 QPainter painter(&buffer); // 在双缓冲区上进行绘制 painter.fillRect(rect(), Qt::white); // 绘制白色背景 painter.setPen(Qt::black); // 设置画笔颜色为黑色 painter.drawLine(0, 0, width(), height()); // 绘制一条线段 // 将双缓冲区的内容绘制到窗口上 painter.begin(this); painter.drawImage(0, 0, buffer); painter.end(); } ``` 2. 在主窗口的构造函数中创建 MyPaintWidget 对象,并将其添加到布局中。 ```cpp MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { MyPaintWidget *paintWidget = new MyPaintWidget(this); setCentralWidget(paintWidget); } ``` 通过以上步骤,我们创建了一个自定义的 QWidget 子类,并在其中实现了双缓冲绘图的功能。在 paintEvent 函数中,首先将绘图操作绘制在双缓冲区(buffer)上,然后再将双缓冲区的内容绘制到窗口上。这样可以避免图形闪烁问题,并提高绘图的效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值