1 #include "DrawingWindow.h"
2 #include <QApplication>
11 #include <QTimerEvent>
12 #include <QWaitCondition>
14 class DrawingThread: public QThread {
16 DrawingThread(DrawingWindow &w, DrawingWindow::ThreadFunction f);
17 void start_once(Priority priority = InheritPriority);
23 DrawingWindow &drawingWindow;
24 DrawingWindow::ThreadFunction threadFunction;
27 friend class DrawingWindow;
28 friend class DrawingWindowPrivate;
31 class DrawingWindowPrivate {
33 static const int paintInterval = 33;
35 DrawingWindow * const q;
40 QWaitCondition paintCondition;
53 DrawingThread *thread;
55 DrawingWindowPrivate(DrawingWindow *w,
56 DrawingWindow::ThreadFunction f);
57 ~DrawingWindowPrivate();
61 void safeLock(QMutex &mutex);
62 void safeUnlock(QMutex &mutex);
65 void dirty(int x, int y);
66 void dirty(int x1, int y1, int x2, int y2);
67 void dirty(const QRect &rect);
71 //--- DrawingWindow ----------------------------------------------------
73 DrawingWindow::DrawingWindow(ThreadFunction f, int w, int h)
77 , d(new DrawingWindowPrivate(this, f))
82 DrawingWindow::DrawingWindow(QWidget *parent,
83 ThreadFunction f, int w, int h)
87 , d(new DrawingWindowPrivate(this, f))
92 DrawingWindow::DrawingWindow(QWidget *parent, Qt::WindowFlags flags,
93 ThreadFunction f, int w, int h)
94 : QWidget(parent, flags)
97 , d(new DrawingWindowPrivate(this, f))
102 DrawingWindow::~DrawingWindow()
107 void DrawingWindow::setColor(float red, float green, float blue)
109 d->fgColor.setRgbF(red, green, blue);
110 QPen pen(d->painter->pen());
111 pen.setColor(d->fgColor);
112 d->painter->setPen(pen);
115 void DrawingWindow::setBgColor(float red, float green, float blue)
117 d->bgColor.setRgbF(red, green, blue);
120 void DrawingWindow::clearGraph()
122 d->safeLock(d->imageMutex);
123 d->painter->fillRect(d->image->rect(), d->bgColor);
125 d->safeUnlock(d->imageMutex);
128 void DrawingWindow::drawPoint(int x, int y)
130 d->safeLock(d->imageMutex);
131 d->painter->drawPoint(x, y);
133 d->safeUnlock(d->imageMutex);
136 void DrawingWindow::drawLine(int x1, int y1, int x2, int y2)
138 d->safeLock(d->imageMutex);
139 d->painter->drawLine(x1, y1, x2, y2);
140 d->dirty(x1, y1, x2, y2);
141 d->safeUnlock(d->imageMutex);
144 void DrawingWindow::drawRect(int x1, int y1, int x2, int y2)
147 r.setCoords(x1, y1, x2, y2);
149 d->safeLock(d->imageMutex);
150 d->painter->drawRect(r);
151 r.adjust(0, 0, 1, 1);
153 d->safeUnlock(d->imageMutex);
156 bool DrawingWindow::sync(unsigned long time)
159 d->safeLock(d->paintMutex);
160 d->safeLock(d->imageMutex);
164 QApplication::postEvent(this, new QPaintEvent(this->rect()));
165 d->dirtyFlag = false;
167 d->safeUnlock(d->imageMutex);
168 ret = d->paintCondition.wait(&d->paintMutex, time);
169 d->safeUnlock(d->paintMutex);
173 void DrawingWindow::sleep(unsigned long secs)
175 DrawingThread::sleep(secs);
178 void DrawingWindow::msleep(unsigned long msecs)
180 DrawingThread::msleep(msecs);
183 void DrawingWindow::usleep(unsigned long usecs)
185 DrawingThread::usleep(usecs);
188 void DrawingWindow::closeEvent(QCloseEvent *ev)
191 d->thread->terminate();
192 d->paintCondition.wakeAll();
193 QWidget::closeEvent(ev);
197 void DrawingWindow::paintEvent(QPaintEvent *ev)
199 QPainter widgetPainter(this);
200 d->imageMutex.lock();
201 QImage imageCopy(*d->image);
202 d->imageMutex.unlock();
203 QRect rect = ev->rect();
204 widgetPainter.drawImage(rect, imageCopy, rect);
205 if (rect == this->rect()) {
206 d->paintMutex.lock();
207 d->paintCondition.wakeAll();
208 d->paintMutex.unlock();
212 void DrawingWindow::showEvent(QShowEvent *ev)
214 d->timer.start(d->paintInterval, this);
215 d->thread->start_once(QThread::IdlePriority);
216 QWidget::showEvent(ev);
219 void DrawingWindow::timerEvent(QTimerEvent *ev)
221 if (ev->timerId() == d->timer.timerId()) {
222 d->imageMutex.lock();
224 update(d->dirtyRect);
225 d->dirtyFlag = false;
227 d->imageMutex.unlock();
228 d->timer.start(d->paintInterval, this);
230 QWidget::timerEvent(ev);
234 //--- DrawingWindowPrivate ---------------------------------------------
236 DrawingWindowPrivate::DrawingWindowPrivate(DrawingWindow *w,
237 DrawingWindow::ThreadFunction f)
240 , image(new QImage(q->width, q->height, QImage::Format_RGB32))
241 , painter(new QPainter(image))
242 , thread(new DrawingThread(*q, f))
246 void DrawingWindowPrivate::initialize()
248 q->setFocusPolicy(Qt::StrongFocus);
249 q->setFixedSize(image->size());
250 q->setAttribute(Qt::WA_OpaquePaintEvent);
253 q->setColor(0.0, 0.0, 0.0); // black
254 q->setBgColor(1.0, 1.0, 1.0); // white
260 DrawingWindowPrivate::~DrawingWindowPrivate()
268 void DrawingWindowPrivate::safeLock(QMutex &mutex)
270 if (lockCount++ == 0)
271 thread->setTerminationEnabled(false);
276 void DrawingWindowPrivate::safeUnlock(QMutex &mutex)
279 if (--lockCount == 0)
280 thread->setTerminationEnabled(true);
284 void DrawingWindowPrivate::dirty()
287 dirtyRect = image->rect();
291 void DrawingWindowPrivate::dirty(int x, int y)
293 dirty(QRect(x, y, 1, 1));
297 void DrawingWindowPrivate::dirty(int x1, int y1, int x2, int y2)
300 r.setCoords(x1, y1, x2, y2);
301 dirty(r.normalized());
304 void DrawingWindowPrivate::dirty(const QRect &rect)
314 //--- DrawingThread ----------------------------------------------------
316 DrawingThread::DrawingThread(DrawingWindow &w, DrawingWindow::ThreadFunction f)
319 , started_once(false)
323 void DrawingThread::start_once(Priority priority)
331 void DrawingThread::run()
333 threadFunction(drawingWindow);