Название: Программа, отрисовывающая точки тремя потоками
Отправлено: libertas от Март 26, 2014, 22:32
Всем привет! Помогите, пожалуйста, разобраться в написании программы, в которой должны быть три потока и эти потоки рисуют свои точки. Должны в итоги получится 3 прерывистые линии, каждая идущая на своем уровне: Вот что я сделал: В хедере: класс главного окна: #ifndef MAINWINDOW_H #define MAINWINDOW_H
#include <QMainWindow> #include <windows.h> #include <QPainter> #include <QColor>
namespace Ui { class MainWindow; }
class MyPoint; class MyData;
class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); //bool res = SetProcessAffinityMask(GetCurrentProcess(), 1); void paintVector(); static DWORD WINAPI ThreadFunction(LPVOID lpParam); protected: void virtual paintEvent(QPaintEvent*);
private: Ui::MainWindow *ui; static QVector<MyPoint> vPoints; static int currentX;
HANDLE handles[3]; static CRITICAL_SECTION* crSecPtr;
static MyData* th1Ptr; static MyData* th2Ptr; static MyData* th3Ptr; private slots: void RepaintSlot(); void on_NoSync_clicked(); }; создал вспомагательный класс для точки и данных, которые будут передаваться в потоковую функцию: class MyPoint { QColor m_col; QPoint m_pt; public: MyPoint(const QPoint& pt = QPoint(), QColor col = QColor(Qt::red)); void paint(QPainter& pe); ~MyPoint(){}
friend class MainWindow; };
class MyData : public QObject { Q_OBJECT int y; int maxX; QColor col; HANDLE hObject; public: MyData(int, int, QColor, HANDLE); ~MyData(){} void SendNeedReDraw(MyPoint&); signals: void needRedraw(MyPoint&); }; А вот, что получилось написать в .срр: #include "mainwindow.h" #include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this);
}
QVector<MyPoint> MainWindow::vPoints;
MainWindow::~MainWindow() { delete ui; }
void MainWindow::paintEvent(QPaintEvent* pe) { QPainter p(this); if (vPoints.isEmpty()) return; for (int i = 0; i < vPoints.size(); i++){ vPoints[i].paint(p); } }
DWORD WINAPI MainWindow::ThreadFunction(LPVOID myData){ MyPoint newPoint(QPoint(currentX, myData->y), myData->col); vPoints.append(newPoint); myData->SendNeedReDraw(myData); }
void MainWindow::RepaintSlot(){ repaint(); }
MyPoint::MyPoint(const QPoint &pt, QColor col){ m_pt = pt; m_col = col; }
void MyPoint::paint(QPainter& p){ QPen pen(m_col); pen.setWidth(5); p.setPen(pen); p.drawPoint(m_pt); }
MyData::MyData(int y, int maxX, QColor col, HANDLE hObject){ this->y = y; this->maxX = maxX; this->col = col; this->hObject = hObject; }
void MyData::SendNeedReDraw(MyPoint& point){ emit needRedraw(point); }
void MainWindow::on_NoSync_clicked() { } Я не знаю, что дальше ещё написать / исправить, что у меня запускались три потока и каждый рисовал свою линию на своем уровне и они рисовались попеременно. Буду очень благодарен, если кто подскажет. Спасибо.
Название: Re: Программа, отрисовывающая точки тремя потоками
Отправлено: vizir.vs от Март 27, 2014, 10:46
Используй mutex, для того, чтобы каждый поток рисовал попеременно. В начале функции Paint он будет у тебя блокироваться, в конце разблокироваться. Судя по описанию это лаба, можно не заморачиваться с QThread и воспользоваться QtConcurrent::run. Туда ты будешь передавать ту функцию, которую надо выполнить в отдельном потоке.
Название: Re: Программа, отрисовывающая точки тремя потоками
Отправлено: libertas от Март 27, 2014, 11:16
Спасибо. Только я не понимаю, я объявил потоковую функцию: static DWORD WINAPI ThreadFunction(LPVOID lpParam); Где мне её вызывать, чтоб запустить поток и как? И что в ней должно быть реализовано? То есть сейчас у меня такой код в ней: DWORD WINAPI MainWindow::ThreadFunction(LPVOID myData){ MyPoint newPoint(QPoint(currentX, myData->y), myData->col); vPoints.append(newPoint); myData->SendNeedReDraw(myData); } но я не понимаю во-первых, что передавать ей в качестве параметра. У неё тип lpvoid, а во-вторых как работает вызов метода: myData->SendNeedReDraw(myData); то есть как она будет рисовать.
Название: Re: Программа, отрисовывающая точки тремя потоками
Отправлено: vizir.vs от Март 27, 2014, 11:36
у тебя будет функция типа void DrawPoint(QWidget* widget, const QVector<QPoint>& point) { for (size_t i = 0; i < point.size(); i++) { блокируешь мьютекс рисуешь точку на виджете разблокировал мьютекс } }
Дальше ты через qtconcurrent::run(DrawPoint, myWidget, myPoint); запускаешь выполнение функции DrawPoint в отдельном потоке.
Название: Re: Программа, отрисовывающая точки тремя потоками
Отправлено: libertas от Март 27, 2014, 14:09
У меня в главном окне приложения: перегружен метод перерисовки: void MainWindow::paintEvent(QPaintEvent* pe) { QPainter p(this); if (vPoints.isEmpty()) return; for (int i = 0; i < vPoints.size(); i++){ vPoints[i].paint(p); } } Сам метод paint реализован вот так( точка рисуется): void MyPoint::paint(QPainter& p){ QPen pen(m_col); pen.setWidth(5); p.setPen(pen); p.drawPoint(m_pt); } У меня есть кнопка No_sync: void MainWindow::on_NoSync_clicked() { } Здесь я так понимаю мне нужно прописать запуск потоков. Нужно запустить через функцию CreateThread. Мне для начала нужно просто их запустить без мьютексов. Посмотреть как потоки будут распределять процессорное время и рисоваться. Для этого мне нужно в эту функцию передать потоковую функцию. Спасибо, стало понятней, буду разбираться дальше!
Название: Re: Программа, отрисовывающая точки тремя потоками
Отправлено: Bepec от Март 27, 2014, 14:21
Ну и если ты хочешь использовать Qt, тогда лучше тебе бы использовать QThread или moveToThread. А то сейчас ты используешь winApi :)
Название: Re: Программа, отрисовывающая точки тремя потоками
Отправлено: libertas от Март 27, 2014, 14:46
Согласен. Просто у нас лабы по winapi, а делать их нужно в qt. Поэтому использую функции winapi и классы qt для графики.
Название: Re: Программа, отрисовывающая точки тремя потоками
Отправлено: libertas от Март 27, 2014, 14:56
Запускать потоки стал так: может кому - когда пригодится: QColor arColor[3] = {Qt::red, Qt::green, Qt::blue}; void MainWindow::on_NoSync_clicked()
{ // 1)подготовка к новому рисованию,почистить вектор, установиться в начало рисования, перерисовать область vPoints.clear(); currentX = 0; repaint();
const int n = 3; // задаем количество потоков int y = 200; // задаем начальную координату y int npoints = geometry().width()/4; // задаем количество точек для рисования, например так или задаем значение // объект синхронизации создан ранее в конструкторе //создаем массив динамических объектов (уничтожать будем при завершении потока), которые будем передавать в поток
for (int i=0; i<n; i++) {
//создаются три динамических объекта MyData (y,maxX,HANDLE hObject) pdata[i]= new MyData(y, npoints, arColor[i], 0); y+=50; //потоки для рисования создаем в заснувшем состоянии // потоковой функции передается своя структура данных handles[i] = ::CreateThread(0,0,ThreadFunction, pdata[i],CREATE_SUSPENDED,0);
// связываем сигнал от объекта pdata[i] со слотом в MainWindow, который добавляет точку в вектор и перерисовывает окно QObject::connect(pdata[i], SIGNAL(needRedraw(MyPoint)), this, SLOT(addPoint(MyPoint)), Qt::BlockingQueuedConnection); } for (int i=0; i<n; i++) { //пробуждаются потоки ResumeThread(handles[i]);
//закрываем дескрипторы потоков CloseHandle(handles[i]); } } Единственное не очень понял, что значит параметр Qt::BlockingQueuedConnection. Может, кто знает?
|