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 QApplication::postEvent(this, new QEvent(QEvent::User));
161 ret = d->paintCondition.wait(&d->paintMutex, time);
162 d->safeUnlock(d->paintMutex);
166 void DrawingWindow::sleep(unsigned long secs)
168 DrawingThread::sleep(secs);
171 void DrawingWindow::msleep(unsigned long msecs)
173 DrawingThread::msleep(msecs);
176 void DrawingWindow::usleep(unsigned long usecs)
178 DrawingThread::usleep(usecs);
181 void DrawingWindow::closeEvent(QCloseEvent *ev)
184 d->thread->terminate();
185 d->paintCondition.wakeAll();
186 QWidget::closeEvent(ev);
190 void DrawingWindow::customEvent(QEvent *)
192 d->imageMutex.lock();
194 QRect r = d->dirtyRect;
195 d->dirtyFlag = false;
196 d->imageMutex.unlock();
199 d->imageMutex.unlock();
200 d->paintMutex.lock();
201 d->paintCondition.wakeAll();
202 d->paintMutex.unlock();
205 void DrawingWindow::keyPressEvent(QKeyEvent *ev)
220 void DrawingWindow::paintEvent(QPaintEvent *ev)
222 QPainter widgetPainter(this);
223 d->imageMutex.lock();
224 QImage imageCopy(*d->image);
225 d->imageMutex.unlock();
226 QRect rect = ev->rect();
227 widgetPainter.drawImage(rect, imageCopy, rect);
230 void DrawingWindow::showEvent(QShowEvent *ev)
232 d->timer.start(d->paintInterval, this);
233 d->thread->start_once(QThread::IdlePriority);
234 QWidget::showEvent(ev);
237 void DrawingWindow::timerEvent(QTimerEvent *ev)
239 if (ev->timerId() == d->timer.timerId()) {
240 d->imageMutex.lock();
242 update(d->dirtyRect);
243 d->dirtyFlag = false;
245 d->imageMutex.unlock();
246 d->timer.start(d->paintInterval, this);
248 QWidget::timerEvent(ev);
252 //--- DrawingWindowPrivate ---------------------------------------------
254 DrawingWindowPrivate::DrawingWindowPrivate(DrawingWindow *w,
255 DrawingWindow::ThreadFunction f)
258 , image(new QImage(q->width, q->height, QImage::Format_RGB32))
259 , painter(new QPainter(image))
260 , thread(new DrawingThread(*q, f))
264 void DrawingWindowPrivate::initialize()
266 q->setFocusPolicy(Qt::StrongFocus);
267 q->setFixedSize(image->size());
268 q->setAttribute(Qt::WA_OpaquePaintEvent);
271 q->setColor(0.0, 0.0, 0.0); // black
272 q->setBgColor(1.0, 1.0, 1.0); // white
278 DrawingWindowPrivate::~DrawingWindowPrivate()
286 void DrawingWindowPrivate::safeLock(QMutex &mutex)
288 if (lockCount++ == 0)
289 thread->setTerminationEnabled(false);
294 void DrawingWindowPrivate::safeUnlock(QMutex &mutex)
297 if (--lockCount == 0)
298 thread->setTerminationEnabled(true);
302 void DrawingWindowPrivate::dirty()
305 dirtyRect = image->rect();
309 void DrawingWindowPrivate::dirty(int x, int y)
311 dirty(QRect(x, y, 1, 1));
315 void DrawingWindowPrivate::dirty(int x1, int y1, int x2, int y2)
318 r.setCoords(x1, y1, x2, y2);
319 dirty(r.normalized());
322 void DrawingWindowPrivate::dirty(const QRect &rect)
332 //--- DrawingThread ----------------------------------------------------
334 DrawingThread::DrawingThread(DrawingWindow &w, DrawingWindow::ThreadFunction f)
337 , started_once(false)
341 void DrawingThread::start_once(Priority priority)
349 void DrawingThread::run()
351 threadFunction(drawingWindow);