<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                本系列所有文章可以在這里查看[http://blog.csdn.net/cloud_castle/article/category/2123873](http://blog.csdn.net/cloud_castle/article/category/2123873) 這個例子可能是我們Clock系列的最后一個例程了,它又有什么特別之處呢?我們來看看吧~ The Analog Clock Window example shows how to draw the contents of a custom window. ![](https://box.kancloud.cn/2016-01-18_569cbd013a69c.jpg) This example demonstrates how the transformation and scaling features of QPainter can be used to make drawing easier. 我個人是不太喜歡翻譯這兩段英文,因為如果有翻譯的話大家可能就不會去看這兩段話了,可是我又不能保證把原文的意思都清晰地翻譯出來,請原諒我一生放蕩不羈語死早。。。 好了,回正題,這個例子其實挺有意思的,它使用了一個我們并不太常見的QWindow。了解它可能會使我們進一步了解Qt的窗口機制。來看源碼~ 這個例子用到了我們之前都沒見過的.pri文件,這是個什么東西?讓我們把.pro和.pri放在一起看: analogclock.pro: ~~~ include(../rasterwindow/rasterwindow.pri) # work-around for QTBUG-13496 CONFIG += no_batch SOURCES += \ main.cpp target.path = $$[QT_INSTALL_EXAMPLES]/gui/analogclock INSTALLS += target ~~~ rasterwindow.pri: ~~~ INCLUDEPATH += $$PWD SOURCES += $$PWD/rasterwindow.cpp HEADERS += $$PWD/rasterwindow.h ~~~ 好像是第一次講Qt的pro文件,其實我們很有必要理清這個小小的pro文件到底帶給了我們什么東西,我們一句一句看: 首先,pri是什么,簡單來說,可以理解為(project include),即包含工程。在做實際項目的時候,大多數情況下我們用到的類可能并不是自己寫的,而是以打包(文件夾)的形式拿過來,并且,所有的文件都放在一個目錄似乎也難以維護。那么我們創建一個pri文件,并在pro中include它就好了,而include(../rasterwindow/rasterwindow.pri)將被展開成pri文件中的內容。(../是什么?一個"."是當前目錄,兩個"."是上級目錄)另外,Qt中還有.prf和.prl文件,具體可參考淺談 qmake 之 pro、pri、prf、prl文件](http://blog.csdn.net/dbzhang800/article/details/6348432)> 那么 PWD又是什么呢?在qmake工程文件中,我們可以利用 var來取一個變量var的值,這里的PWD就是當前目錄的絕對路徑了。 OK,現在我們把.pri文件中的內容在.pro中展開,第二句我們又糊涂了,CONFIG += no_batch似乎是為了解決QTBUG-13496這個Bug存在的。那如果我們想知道這個Bug是什么,帖這段網址去看看https://bugreports.qt-project.org/browse/QTBUG-13496。Qt官方對這個Bug是這么描述的:nmake gives a wrong source file to the compiler 然后在下面一般會有合適的解決方案。 $$[QT_INSTALL_EXAMPLES],這里的QT_INSTALL_EXAMPLES是Qt配置選項的值,它不是一個變量,是你裝好Qt以后就定好的一個值,這里是你Qt官方demo的頂層絕對路徑。有關qmake的各項參數,具體可以參考qmake 亂亂亂談(一)](http://blog.csdn.net/dbzhang800/article/details/6758204)> 既然談到了pro文件,Qt += XXX不得不談,既然要編譯程序,無非就是預處理、編譯和鏈接,編譯預處理要展開我們的宏,展開包含的頭文件,鏈接時呢,我們需要鏈接器能找到我們的庫。 Qt在pro文件中實際上默認省略了兩句話 CONFIG += qt 和 QT += core。第一句話告訴qmake,你可以到$QTDIR/include目錄下去找頭文件。當然,因為這個目錄下都是文件夾,qmake找不到實際的頭文件。然后它又告訴qmake,“我們的庫文件路徑在$QTDIR/lib里面~”。 第二句話QT += core就細分了,它告訴qmake,頭文件路徑可以向下一層,即$QTDIR/include/QtCore。鏈接需要的庫呢,指定了一個QtCore4.lib。并定義宏QT_CORE_LIB 我們可以在QtCore文件夾里找到我們熟悉的QString,這就是我們在編寫小程序用到QString卻不需要#include的原因。 好,我們現在來理一下這個思路。QT += XXX 實際上是為我們指明了一個路徑。如果我們沒有在pro文件中添加 QT += network ,然后#include出現什么情況?有個波浪線出來了吧,提示是,“QTcpSocket:沒有這個文件或目錄”。這就是因為在Qt在include目錄下找不到名為QTcpSocket的文件或者目錄。 那好說啊,我們這樣#include不就能找到了嗎?是的,可以看到波浪線沒了,說明這個頭文件確實能被找到,但是別忘了QT += XXX還提供了我們在鏈接時需要用到的庫。如果在單步編譯這個Qt程序的話,可以看到編譯過了,程序會在鏈接時報錯。 好了,隨便一講講了這么多,先來看RasterWindow類的實現。rasterwindow.h: ~~~ #ifndef RASTERWINDOW_H #define RASTERWINDOW_H //! [1] #include <QtGui> class RasterWindow : public QWindow { Q_OBJECT public: explicit RasterWindow(QWindow *parent = 0); virtual void render(QPainter *painter); // 定義了一個需要子類繼承的虛Render<span style="font-family: Arial, Helvetica, sans-serif;">(QPainter *painter)</span><span style="font-family: Arial, Helvetica, sans-serif;">函數用來進行繪圖</span> public slots: void renderLater(); void renderNow(); protected: bool event(QEvent *event); // 重寫了三個事件 void resizeEvent(QResizeEvent *event); void exposeEvent(QExposeEvent *event); private: QBackingStore *m_backingStore; bool m_update_pending; // 作為窗口更新的標志位 }; //! [1] #endif // RASTERWINDOW_H ~~~ 與往常不同的是,這個RasterWindow繼承的是QWindow類,而不是我們熟悉的QWidget,它們有什么區別呢?大家都知道,QWidget及其眾多的子類在Qt5中已經從QtGui模塊中移除,成為了獨立的QtWidgets,但是這個QWindow依然是屬于QtGui模塊的。也就是說,使用QWindow,我們不需要包含QtWidgets模塊。 而QPainter也是被QtGui所包含的,因此我們僅包含QtGui就可以創建一個簡單的窗口了。 QBackingStore類可以簡單的理解為專為QWindow繪圖所提供的類,同樣屬于QtGui。因此一般來說這個類是當我們想要使用QPainter但又不想使用OpenGL、QWidget、QGraphicsView帶來額外開銷的時候來使用的。 rasterwindow.cpp: ~~~ #include "rasterwindow.h" //! [1] RasterWindow::RasterWindow(QWindow *parent) : QWindow(parent) , m_update_pending(false) { m_backingStore = new QBackingStore(this); create(); // 通過平臺資源創建一個窗口 setGeometry(100, 100, 300, 200); // 顯示位置 } //! [1] //! [7] bool RasterWindow::event(QEvent *event) { if (event->type() == QEvent::UpdateRequest) { // 當窗口需要重繪時觸發 m_update_pending = false; renderNow(); return true; } return QWindow::event(event); } //! [7] //! [6] void RasterWindow::renderLater() // 這個函數是被外部調用的 { if (!m_update_pending) { m_update_pending = true; QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); // 手動派發事件 } } //! [6] //! [5] void RasterWindow::resizeEvent(QResizeEvent *resizeEvent) // 僅當窗口isExposed時進行重繪 { m_backingStore->resize(resizeEvent->size()); if (isExposed()) renderNow(); } //! [5] //! [2] void RasterWindow::exposeEvent(QExposeEvent *) { if (isExposed()) { renderNow(); } } //! [2] //! [3] void RasterWindow::renderNow() { if (!isExposed()) return; QRect rect(0, 0, width(), height()); m_backingStore->beginPaint(rect); // 確定繪制區域 QPaintDevice *device = m_backingStore->paintDevice(); // QBackingStore->QPaintDevice->QPainter QPainter painter(device); painter.fillRect(0, 0, width(), height(), Qt::white); // 繪制了一個白色背景 render(&painter); m_backingStore->endPaint(); m_backingStore->flush(rect); // 記得結束和刷新 } //! [3] //! [4] void RasterWindow::render(QPainter *painter) // 實現了自己的虛函數,因為被重寫因此我們看不到這行QWindow { painter->drawText(QRectF(0, 0, width(), height()), Qt::AlignCenter, QStringLiteral("QWindow")); } //! [4] ~~~ 注意到倒數第三行的QStringLiteral,為什么不用QString?我們來看Manual怎么說的: If you have code looking like: if (node.hasAttribute("http-contents-length")) //... One temporary QString will be created to be passed as the hasAttribute function parameter. This can be quite expensive, as it involves a memory allocation and the copy and the conversion of the data into QString's internal encoding. This can be avoided by doing if (node.hasAttribute(QStringLiteral("http-contents-length"))) //... Then the QString's internal data will be generated at compile time and no conversion or allocation will occur at runtime Using QStringLiteral instead of a double quoted ascii literal can significantly speed up creation of QString's from data known at compile time. 也就是說,如果直接“...”這種形式的常量字符,Qt將為它創建一個臨時的QString對象,這需要申請內存,轉換成QString的編碼等等許多工作,而這對于一個常量而言代價是很大的。因此Qt提供了QStringLiteral的包裝方式,它在編譯期間就創建了這個QString的內部數據(也就是utf16字符串),從而在運行期不再需要申請內存和數據轉換,并且相比前者也減少了編譯時間。 最后來看main.cpp: ~~~ #include <QtGui> #include "rasterwindow.h" //! [5] class AnalogClockWindow : public RasterWindow { public: AnalogClockWindow(); protected: void timerEvent(QTimerEvent *); // 通過timerEvent,我們能夠使用更多定時器的功能 void render(QPainter *p); private: int m_timerId; // 這個數據成員用來存儲定時器ID }; //! [5] //! [6] AnalogClockWindow::AnalogClockWindow() { setTitle("Analog Clock"); resize(200, 200); m_timerId = startTimer(1000); // 存儲這個定時器ID } //! [6] //! [7] void AnalogClockWindow::timerEvent(QTimerEvent *event) // 當timeout時事件被觸發 { if (event->timerId() == m_timerId) // 確定事件來自這個定時器。盡管這里有點多余,但它是個好習慣。 renderLater(); // 提交update事件而不是強制重繪通常是種更好的選擇 } //! [7] //! [1] //! [14] void AnalogClockWindow::render(QPainter *p) //<span style="font-family: 'Microsoft YaHei'; font-size: 20px; line-height: 30px;"> </span>繪圖代碼參見Analog Clock Example { //! [14] //! [8] static const QPoint hourHand[3] = { QPoint(7, 8), QPoint(-7, 8), QPoint(0, -40) }; static const QPoint minuteHand[3] = { QPoint(7, 8), QPoint(-7, 8), QPoint(0, -70) }; QColor hourColor(127, 0, 127); QColor minuteColor(0, 127, 127, 191); //! [8] //! [9] p->setRenderHint(QPainter::Antialiasing); //! [9] //! [10] p->translate(width() / 2, height() / 2); int side = qMin(width(), height()); p->scale(side / 200.0, side / 200.0); //! [1] //! [10] //! [11] p->setPen(Qt::NoPen); p->setBrush(hourColor); //! [11] //! [2] QTime time = QTime::currentTime(); p->save(); p->rotate(30.0 * ((time.hour() + time.minute() / 60.0))); p->drawConvexPolygon(hourHand, 3); p->restore(); //! [2] //! [12] p->setPen(hourColor); for (int i = 0; i < 12; ++i) { p->drawLine(88, 0, 96, 0); p->rotate(30.0); } //! [12] //! [13] p->setPen(Qt::NoPen); p->setBrush(minuteColor); //! [13] //! [3] p->save(); p->rotate(6.0 * (time.minute() + time.second() / 60.0)); p->drawConvexPolygon(minuteHand, 3); p->restore(); //! [3] //! [4] p->setPen(minuteColor); for (int j = 0; j < 60; ++j) { if ((j % 5) != 0) p->drawLine(92, 0, 96, 0); p->rotate(6.0); } //! [4] } int main(int argc, char **argv) { QGuiApplication app(argc, argv); AnalogClockWindow clock; clock.show(); app.exec(); } ~~~ ok,我們的Clock三兄弟的故事就先到這里啦~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看