c++ - Using QPainter to draw a line between QWidgets -
i'm working on application need able draw line between 2 qwidget
objects. have tried quite few things, current attempt (which think in right direction think i'm missing something) have containing widget (which called drawwidget
, holds qgridlayout
qwidget
objects added to) override paintevent
method , call qpainter::drawline()
function.
the issues i'm having that:
- no matter how try position of widgets, endpoints of line in wrong place
- whenever try draw second line, first line drew gets erased.
here paintevent
function of containing widget:
void paintevent(qpaintevent *) { if (!drewsinceupdate){ drewsinceupdate = true; qpainter painter(this); painter.setpen(qpen(qt::black)); painter.drawline(start->geometry().center(), end->geometry().center()); } }
i have tried many different ways correct position of widgets in last line of paintevent
, post of ways (i can't remember of them):
painter.drawline(start->pos(), end->pos()); painter.drawline(start->maptoglobal(start->geometry().center()), end->maptoglobal(end->geometry().center())); painter.drawline(this->maptoglobal(start->geometry().center()), this->maptoglobal(end->geometry().center())); painter.drawline(start->mapto(this, start->pos()), end->mapto(this, end->pos())); painter.drawline(this->mapfrom(start, start->pos()), this->mapfrom(end, end->pos()));
and make question clear, here example of looking for, taken qt diagram scene example: end getting:
note:
-start
, end
both qwidget
objects passed in using method
-the hierarchy relevant drawwidget
is:
qmainwindow ->qscrollarea ->drawwidget ->qgridlayout ->items <-- these things want connect
edit: make complete , verifiable example, here entirety of relevant code.
mainwindow.cpp:
#include "mainwindow.h" #include "ui_mainwindow.h" #include <qhboxlayout> #include <qvboxlayout> #include <qtextedit> #include <qpushbutton> #include <qscrollbar> mainwindow::mainwindow(qwidget *parent) : qmainwindow(parent), ui(new ui::mainwindow) { // setting relevant hierarchy ui->setupui(this); scrollarea = new qscrollarea(); setcentralwidget(scrollarea); drawwidget = new drawwidget(); gridlayout = new qgridlayout(); gridlayout->setspacing(300); drawwidget->setlayout(gridlayout); scrollarea->setwidget(drawwidget); scrollarea->setwidgetresizable(true); additemslot(); qapplication::connect(scrollarea->horizontalscrollbar(), signal(rangechanged(int,int)), this, slot(scrollhorizontal())); } // creating single 1 of example widgets want connect qwidget* mainwindow::createnewitem(){ qwidget* itemwidget = new qwidget(); itemwidget->setstylesheet("background-color: lightgray"); qhboxlayout* singleitemlayout = new qhboxlayout(); itemwidget->setlayout(singleitemlayout); qtextedit* textedit = new qtextedit(std::to_string(counter++).c_str()); textedit->setstylesheet("background-color:white;"); singleitemlayout->addwidget(textedit); qvboxlayout* rightsidepanel = new qvboxlayout(); rightsidepanel->setalignment(qt::aligntop); qpushbutton* button1 = new qpushbutton("top button"); qapplication::connect(button1, signal(clicked(bool)), this, slot(additemslot())); rightsidepanel->addwidget(button1); qwidget* rightpanelwidget = new qwidget(); rightsidepanel->setmargin(0); rightpanelwidget->setlayout(rightsidepanel); singleitemlayout->addwidget(rightpanelwidget); itemwidget->setlayout(singleitemlayout); itemwidget->setminimumwidth(400); itemwidget->setfixedsize(400,200); return itemwidget; } mainwindow::~mainwindow() { delete ui; } void mainwindow::scrollhorizontal() { scrollarea->ensurewidgetvisible(noteitems.back()); } void mainwindow::additemslot() { qwidget* w = createnewitem(); gridlayout->addwidget(w,currrow, currcol++); if (!noteitems.empty()){ drawwidget->updateendpoints(noteitems.back(), w); } noteitems.push_back(w); }
mainwindow.h
#ifndef mainwindow_h #define mainwindow_h #include <qgridlayout> #include <qwidget> #include <qmainwindow> #include <qscrollarea> #include <drawwidget.h> #include "drawscrollarea.h" #include <vector> namespace ui { class mainwindow; } class mainwindow : public qmainwindow { q_object public: explicit mainwindow(qwidget *parent = 0); ~mainwindow(); public slots: void scrollhorizontal(); void additemslot(); private: ui::mainwindow *ui; qwidget* createnewitem(); int counter = 0, currcol = 0, currrow = 0; std::vector<qwidget*> noteitems; qscrollarea* scrollarea; drawwidget* drawwidget; qgridlayout* gridlayout; }; #endif // mainwindow_h
drawwidget.cpp:
#include "drawwidget.h" #include <qdebug> #include <qrect> drawwidget::drawwidget(qwidget *parent) : qwidget(parent) { } void drawwidget::paintevent(qpaintevent *) { if (!drewsinceupdate){ drewsinceupdate = true; qpainter painter(this); painter.setpen(qpen(qt::black)); (connectedpair pair : items){ const qwidget* = pair.from; const qwidget* =pair.to; qpoint start = from->maptoglobal(from->rect().topright() + qpoint(0, from->height()/2)); qpoint end = to->maptoglobal(to->rect().topleft() + qpoint(0, to->height()/2)); painter.drawline(mapfromglobal(start), mapfromglobal(end)); } } } void drawwidget::updateendpoints(qwidget* startin, qwidget* endin){ drewsinceupdate = false; items.push_back(connectedpair{startin, endin}); }
drawwidget.h
#ifndef drawwidget_h #define drawwidget_h #include <qwidget> #include <qpainter> #include <qtcore> #include <vector> class drawwidget : public qwidget { q_object public: explicit drawwidget(qwidget *parent = nullptr); void updateendpoints(qwidget* startin, qwidget* endin); virtual void paintevent(qpaintevent *); signals: private: struct connectedpair { const qwidget* from; const qwidget* to; }; std::vector<connectedpair> items; bool drewsinceupdate = true; }; #endif // drawwidget_h
for case use function maptoglobal() , mapfromglobal(), since pos() returns position respect parent , can cause problems if widget has different parents.
drawwidget.h
#ifndef drawwidget_h #define drawwidget_h #include <qwidget> class drawwidget : public qwidget { q_object public: explicit drawwidget(qwidget *parent = nullptr); void addwidgets(const qwidget *from, const qwidget *to); protected: void paintevent(qpaintevent *); private: struct widgetsconnected { const qwidget* from; const qwidget* to; }; qlist<widgetsconnected> list; }; #endif // drawwidget_h
drawwidget.cpp
#include "drawwidget.h" #include <qpainter> drawwidget::drawwidget(qwidget *parent) : qwidget(parent) { } void drawwidget::addwidgets(const qwidget * from, const qwidget * to) { list.append(widgetsconnected{from , to}); update(); } void drawwidget::paintevent(qpaintevent *) { qpainter painter(this); for(const widgetsconnected el: list){ const qwidget* = el.from; const qwidget* = el.to; qpoint start = from->maptoglobal(from->rect().topright() + qpoint(0, from->height()/2)); qpoint end = to->maptoglobal(to->rect().topleft() + qpoint(0, to->height()/2)); painter.drawline(mapfromglobal(start), mapfromglobal(end)); } }
the complete example can found here.
Comments
Post a Comment