雙緩沖技術(Double Buffering)( 2、公有函數實現)
#include <QtGui>
#include <cmath>
using namespace std;
#include "plotter.h"
以上代碼為文件的開頭,在這里把std 的名空間加入到當前的全局命名空間。這樣在使用<cmath>里的函數時,就不用前綴 std::了,如可以直接使用函數 floor(),而不用寫成 std::floor()。
Plotter::Plotter(QWidget *parent) : QWidget(parent)
{
setBackgroundRole(QPalette::Dark); setAutoFillBackground(true); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setFocusPolicy(Qt::StrongFocus);
rubberBandIsShown = false;zoomInButton = new QToolButton(this);
zoomInButton->setIcon(QIcon(":/images/zoomin.png")); zoomInButton->adjustSize();
connect(zoomInButton, SIGNAL(clicked()), this, SLOT(zoomIn()));zoomOutButton = new QToolButton(this);
zoomOutButton->setIcon(QIcon(":/images/zoomout.png")); zoomOutButton->adjustSize();
connect(zoomOutButton, SIGNAL(clicked()), this, SLOT(zoomOut()));setPlotSettings(PlotSettings());
}
在構造函數中,調用setBackGroundRole(QPalette::Dark),當對控件進行放大需要重新繪制時,提供給Qt 一個缺省的顏色填充新的區域,為了能夠使用這個機制,還調用了 setAutoFillBackground(true)。函數setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)讓控件在水平和垂直兩個方向上都可以進行伸縮。如果控件需要占據屏幕上很大的控件,經常設置這個屬性。缺省的設置是兩個方向都是 QSizePolicy::Preferred,意思是控件的實際尺寸和它的 sizeHint一致,控件最小只能縮小到它的最小的 sizeHint,并能夠無限放大。
調用setFocusPolicy(Qt::StrongFocus)可以使控件通過鼠標點擊或者Tab 得到焦點。當 Plotter 控件得到焦點時,它可以接受鍵盤敲擊事件。Plotter 控件能夠理解一些鍵盤事件,如+放大,-為縮小,可以向上下左右平移。
在構造函數中,我們還創建了兩個QToolButton,每一個按鈕都有一個圖標。點擊這些圖標可以放大或者縮小顯示的圖像。圖標保存在資源文件中,為了任何程序都可以使用 Plotter 控件,需要在.pro 添加資源條目:
RESOURCES????? = plotter.qrc
資源文件是一個XML 格式的文本文件,和在Spreadsheet 中使用的很像:
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>images/zoomin.png</file>
<file>images/zoomout.png</file>
</qresource>
</RCC>
調用QToolButton::adjustSize()調整按鈕的大小為它們的sizeHint。在這里按鈕不在布局中 ,在控件大小改變的時候,又程序計算它們的位置。由于沒有了布局管理,因為我們必須在按鈕的構造函數中確定按鈕的父控件。調用setPlotSettings()函數用來完成控件的初始化。函數代碼如下:
void Plotter::setPlotSettings(const PlotSettings &settings)
{
zoomStack.clear(); zoomStack.append(settings); curZoom = 0;
zoomInButton->hide(); zoomOutButton->hide();refreshPixmap();
}
函數setPlotSettings()確定顯示控件時的PlotSettings。它在Plotter 構造函數中調用,也可以被Plotter 的用戶調用。開始的時候,Plotter 使用的是缺省的放縮值。用戶進行放大一次,就有一個新的PlotSettings 對象加入到堆棧中。這個堆棧中有兩個變量:
zoomStack 是保存PlotSettings 對象的一個數組;
curZoom 是當前使用的 PlotSettings 的一個索引值。
調用setPlotSettings()后,zoomStack 中只有一項,zoomIn 和zoomOut 按鈕隱藏。如果我們調用函數zoomIn()和zoomOut(),這兩個函數中調用了按鈕的show()函數,它們才能顯示出來。(通常,調用父控件的 show()函數就顯示所有的子控件。但是如果我們顯式調用了子控件的hide(),必須要顯示調用其show()函數顯示它,否則就會一直隱藏)
調用refreshPixmap()來更新顯示。通常,我們調用 update()就可以,這里有些不一樣,因為我們要保持QPixmap 一直最新的狀態。更新了圖片后,refreshPixmap()再調用update()把圖片顯示到控件上。
void Plotter::zoomOut()
{
if (curZoom > 0) {
--curZoom;
zoomOutButton->setEnabled(curZoom > 0); zoomInButton->setEnabled(true); zoomInButton->show();
refreshPixmap();
}
}
如果圖片放大了,調用 zoomOut()縮小它。它縮小比例系數,如果還能進一步縮小,zoomOut
按鈕一直有效。顯示zoomIn 按鈕使之按鈕有效,調用refreshPixmap()刷新控件。
void Plotter::zoomIn()
{
if (curZoom < zoomStack.count() - 1) {
++curZoom;
zoomInButton->setEnabled(curZoom < zoomStack.count() - 1); zoomOutButton->setEnabled(true);
zoomOutButton->show(); refreshPixmap();
}
}
如果用戶放大后又縮小控件,下一個放縮系數的 PlotSettings 就進入zoomStack。我們就可以再放大控件。函數zoomIn 增加放縮系數,zoomIn 按鈕顯示出來,只要能夠放大,按鈕會一直有效。同事顯示zoomOut 按鈕使之有效狀態。
void Plotter::setCurveData(int id, const QVector<QPointF> &data)
{
curveMap[id] = data; refreshPixmap();}
函數setCurveData()設置一個指定id 的曲線數據。如果曲線中有一個同樣的 id,那么就用新的數據替代舊數據。如果沒有指定的id,則增加一個新的曲線。曲線的數據類型為QMap<int, QVector<QPointF> >
void Plotter::clearCurve(int id)
{
curveMap.remove(id); refreshPixmap();
}
函數clearCurve()刪除一個指定id 的曲線。
QSize Plotter::minimumSizeHint() const
{
return QSize(6 * Margin, 4 * Margin);
}
函數minimumSizeHint()和sizeHint()很像,確定控件的理想的尺寸。minimumSizeHint()
確定控件的最大尺寸。布局管理器排列控件時不會超過控件的最大尺寸。由于Margin 值為 50,所以我們返回的值為 300×200,包括四個邊界的寬度和 Plot 本身。如果再小,尺寸太小Plot 就不能正常顯示了。
QSize Plotter::sizeHint() const
{
return QSize(12 * Margin, 8 * Margin);
}
在sizeHint()中,我們返回控件的理想尺寸,用 Margin 常數作為倍數,長寬的比例為 3:2,與minimumSizeHint()中比例一致。
以上是Plotter 的公有函數和槽函數。