PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [Qt] Linien dynamisch auf Label zeichnen



melanie
24-08-2010, 12:07
Hallo,
ich schreibe an einem Programm (abgewandelter ImageViewer aus den Beispielprogrammen) und möchte ein Bild verkleinern, dass gerade auf dem QLabel angezeigt wird. Dazu öffne ich einen Dialog und wähle aus, wie viele Pixel rechts, links, oben und unten abgeschnitten werden sollen. Als Hilfe möchte ich gerne, dass 4 (grüne) Linien auf dem Bild (QLabel) gezeigt werden, die symbolisieren, wo abgeschnitten wird.
So etwa:
......|....................|.......
......|....................|.......
-------------------------
......|....................|.......
......|....................|.......
......|....................|.......
......|....................|.......
-------------------------
......|....................|.......
......|....................|.......
Da ich über den Dialog die Position der Linien verändern würde, müssen sie also "beweglich" sein (oder ich muss das Originalbild halt immer neu laden und dann die Linien neu draufsetzen).
Es wäre toll, wenn jemand eine Idee hätte.
Vielen Dank!
melanie

undefined
24-08-2010, 13:49
Also ich würde so etwas mit QRubberBand machen.

melanie
24-08-2010, 14:32
QRubberBand klingt nach der Class Reference nach dem was ich suche!
Bei der Umsetzung bräuchte ich noch etwas Unterstützung :o

Hier mal ein paar Auszüge aus einem Minimalprogramm:
Die Oberfläche habe ich mit dem QtDesigner gemacht. Es ist eigentlich nichts besonderes. 2 Menüpunkte, 1: Rechteck zeichnen (action_Draw_Rect) und 2: Beenden (action_Beenden)

main.cpp:

#include <Qt/qapplication.h>
#include "MainWindow.h"

int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}

MainWindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <Qt/QMainWindow.h>
#include "Forms/Ui_MainWindow.h"

class QAction;
class QLabel;
class QMenu;

class MainWindow : public QMainWindow, protected Ui_MainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = 0);

private slots:
void drawrect();

private:
QImage GenerateQImage(int value);
QLabel *imageLabel;
QRubberBand *rubberBand;
};

#endif

MainWindow.cpp:

#include <Qt/QLabel.h>
#include "MainWindow.h"

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
setupUi(this);
imageLabel = new QLabel(this->centralWidget()); //platziert das Label auf dem Fenster
imageLabel->setBackgroundRole(QPalette::Base);
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
imageLabel->setScaledContents(true);

//Startbild generieren
QImage image = GenerateQImage(255);
imageLabel->setPixmap(QPixmap::fromImage(image));
imageLabel->setVisible(true);

connect(action_Beenden, SIGNAL(triggered()), this, SLOT(close()));
connect(action_Draw_Rect, SIGNAL(triggered()), this, SLOT(drawrect()));
}

QImage MainWindow::GenerateQImage(int value)
{
QImage img_gray(200, 200, QImage::Format_Indexed8);
// Colortable erstellen für Graustufen
QVector<QRgb> grayscales;
for (int i=0; i<256; ++i)
grayscales.push_back(qRgb(i,i,i));
// colortable dem graustufen bild zuweisen
img_gray.setColorTable(grayscales);

for (int z=0; z<200; ++z)
for (int x=0; x<200; ++x)
{
img_gray.setPixel(x,z, value);
}
return img_gray;
}

void MainWindow::drawrect()
{
if (!rubberBand)
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
rubberBand->setGeometry(10,10,50,50);
rubberBand->show();
}

Was mache ich falsch und wie bekomme ich jetzt ein Rechteck der Größe 50x50 an die Position (10,10) auf dem imageLabel?
Danke!!! :)

undefined
24-08-2010, 18:31
Vermute mal falsche Vererbung.


#ifndef RUBBERBAND_H
#define RUBBERBAND_H

#include <QtCore>
#include <QtGui>

class Rubberband : public QMainWindow
{
Q_OBJECT

private:
QPoint startPoint;
QWidget* central;
QRubberBand* band;

protected:
void mousePressEvent(QMouseEvent *);
void mouseMoveEvent(QMouseEvent *);

public:
Rubberband();
~Rubberband();
};

#endif

Code


#include "rubberband.h"

/* QtCore */
#include <QtCore>
#include <QtGui>

Rubberband::Rubberband()
: QMainWindow ()
, startPoint ( QPoint( 0, 0 ) )
{
setObjectName ( "rubberband" );
setMinimumWidth ( 400 );
setMinimumHeight ( 400 );

central = new QWidget( this );
central->setObjectName ( "rubberband.central" );
central->setAutoFillBackground ( false );
central->setMouseTracking ( false );
central->setStyleSheet ( "*{background-color:gray;}" );

band = new QRubberBand(QRubberBand::Rectangle,central);
band->setGeometry( 0, 0, 100, 100 );
band->show();

setCentralWidget ( central );
}

void Rubberband::mousePressEvent(QMouseEvent *event)
{
startPoint = event->pos();
band->setGeometry(QRect(event->pos(), QSize()));
}

void Rubberband::mouseMoveEvent(QMouseEvent *event)
{
band->setGeometry(QRect(startPoint, event->pos()).normalized());
}

Rubberband::~Rubberband()
{}

melanie
25-08-2010, 08:49
Jetzt bin ich schon einen Schritt weiter, aber leider taucht jetzt ein neuer Fehler auf.
Beim Programmende erscheint der Fehler:
"Run-Time Check Failure #2 - Stack around the variable 'mainWindow' was corrupted."

Hier der Programmcode:
main.cpp:

#include <Qt/qapplication.h>
#include "MainWindow.h"

int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}

MainWindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <Qt/QMainWindow.h>
#include "Forms/Ui_MainWindow.h"

class QAction;
class QLabel;
class QMenu;

class MainWindow : public QMainWindow, protected Ui_MainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = 0);

private:
QImage GenerateQImage(int value);
QLabel *imageLabel;
QRubberBand *rubberBand;
};

#endif

MainWindow.cpp:

#include <Qt/QLabel.h>
#include "MainWindow.h"

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
setupUi(this);
imageLabel = new QLabel(this->centralWidget());
imageLabel->setBackgroundRole(QPalette::Base);
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
imageLabel->setScaledContents(true);

//Startbild generieren
QImage image = GenerateQImage(255);
imageLabel->setPixmap(QPixmap::fromImage(image));
imageLabel->setVisible(true);

rubberBand = new QRubberBand(QRubberBand::Rectangle,imageLabel);
rubberBand->setGeometry( 0, 0, 100, 100 );
rubberBand->show();

connect(action_Beenden, SIGNAL(triggered()), this, SLOT(close()));
}

QImage MainWindow::GenerateQImage(int value)
{
QImage img_gray(200, 200, QImage::Format_Indexed8);
// Colortable erstellen für Graustufen
QVector<QRgb> grayscales;
for (int i=0; i<256; ++i)
grayscales.push_back(qRgb(i,i,i));
// colortable dem graustufen bild zuweisen
img_gray.setColorTable(grayscales);

for (int z=0; z<200; ++z)
for (int x=0; x<200; ++x)
{
img_gray.setPixel(x,z, value);
}
return img_gray;
}

locus vivendi
25-08-2010, 10:07
Also nur mit einigen kleinen Veränderungen, damit das hier kompiliert, läuft dein Programm bei mir ohne Fehlermeldung. Valgrind meldet auch nichts verdächtiges. Ich kann auch im Code soweit keinen Fehler entdecken.

Hast du alle generierten Dateien auf dem neusten Stand? Generier noch mal alles neu und kompiliere frisch durch.

melanie
25-08-2010, 13:25
Jetzt läuft es auch bei mir. Ich habe mal das Projekt bereinigt usw. Doofe Sache. Ich habe nämlich auch nicht verstanden, was da falsch sein soll. Vielen Dank für den Tipp!!!

Aber ich wäre ja nicht ich, wenn ich nicht schon wieder eine neue Frage hätte:
Wie kann ich die Farbe QRubberBand ändern. Ich hätte gerne ein ungefülltes (transparentes) Rechteck mit z.B. grünem Rahmen. (Meine Bilder sind immer Graustufenbilder, weshalb ein grauer Rahmen eher ungünstig ist.)

Vielen Dank :)

undefined
25-08-2010, 15:02
Das geht nur wenn du die Klasse QRubberBand ableitest und mit "initStyleOption" diese Veränderst.

melanie
25-08-2010, 15:59
Oh je, das kann ich fürchte ich nicht. Ich definiere also eine neue Klasse, die von QRubberBand erbt. Hier mal ein bisschen Code dazu, wie ich mir das vorstelle. Allerdings fehlen viele Sachen und ich weiß überhaupt nicht, wie ich mit initStyleOption umgehen soll:

myRubberBand.h:

#ifndef MYRUBBERBAND_H
#define MYRUBBERBAND_H

class MyRubberBand: public QRubberBand
{
Q_OBJECT

public:
MyRubberBand(Shape s = Rectangle, QWidget *parent = 0);

protected:
virtual void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index ) const
};

#endif //MYRUBBERBAND

myRubberBand.cpp:

#include "MyRubberBand.h"

MyRubberBand::MyRubberBand(Shape s, QWidget * parent):
QRubberBand(s, parent)
{}

undefined
25-08-2010, 16:44
Hier auf die schnelle ein Beispiel (nicht getestet) ;)


class RubberBand : public QRubberBand
{
Q_OBJECT

protected:
void initStyleOption ( QStyleOptionRubberBand * ) const;
void paintEvent(QPaintEvent * );

public:
RubberBand ( QWidget * parent = 0 );
};



RubberBand::RubberBand( QWidget * parent )
: QRubberBand (QRubberBand::Rectangle,parent)
{}

void RubberBand::initStyleOption ( QStyleOptionRubberBand * option ) const
{
if (!option)
return;

option->initFrom(this);
}

void RubberBand::paintEvent( QPaintEvent * event )
{
QPainter painter(this);

QBrush b;
b.setStyle ( Qt::SolidPattern );
b.setColor ( Qt::red );

painter.fillRect( event->rect(), b );
painter.beginNativePainting();
painter.endNativePainting();
}

locus vivendi
25-08-2010, 18:06
Ehrlich gesagt glaube ich nicht, dass es zum Ändern der Farbe nötig oder hilfreich ist, eine neu initStyleOption Funktion zu schreiben. (Überschrieben werden kann diese Funktion übrigens gar nicht, weil sie nicht virtuell ist)

Wie das zu machen wäre scheint mir einfach nicht dokumentiert zu sein, aber mit Qt 4.6.3 geht es jedenfalls indem die Farbe für "WindowText" des QRubberBand-Objektes gesetzt wird. Zumindest der Rahmen wird nämlich mit dieser Farbe gezeichnet.

Das sähre dann ungefähr so aus, beispielsweise:


[Im MainWindow-Konstruktor]
[...]
rubberBand = new QRubberBand(QRubberBand::Rectangle,imageLabel);
QPalette pal = rubberBand->palette();
pal.setColor(QPalette::WindowText, QColor("red") );
rubberBand->setPalette(pal);
[...]


Wie man auch noch eine Hintergrundfarbe setzt, das weiß ich nicht. Ich weiß bloß, das es Code in der Datei src/gui/styles/qcommonstyle.cpp der Qt-Sourcen gibt, die zum Zeichnen der Rubberbands benutzt wird. Da könnte man dann evtl. mal reingucken wie das ginge. Aber wie gesagt, man verlässt damit das was von der Doku garantiert wird.

undefined
25-08-2010, 19:09
Geht schon und ist in einer meiner Projekte im einsatz um den OpenSuSE KDE4 Style (Patch) zu kicken der bei diesem Program hinderlich ist.
http://gitweb.hjcms.de/cgi-bin/index.cgi/qx11grab/tree/src/rubberband.cpp

locus vivendi
25-08-2010, 20:24
Bezüglich initStyleOption neu schreiben/überschreiben:

Geht schon und ist in einer meiner Projekte im einsatz um den OpenSuSE KDE4 Style (Patch) zu kicken der bei diesem Program hinderlich ist.
Aber wie wird die Funktion denn aufgerufen? Sie ist nicht virtuell markiert, auch nicht in einer Basisklasse. Kann es sein, dass der wichtige Part bei dir vielmehr ist, dass du
paintEvent überschreibst? Damit kann man natürlich ganz schön was anstellen...

undefined
26-08-2010, 13:28
Ja der wichtige Part ist in der tat der paintEvent. Soweit ich mich erinnere bekommt die Methode initStyleOption nur dann eine Bedeutung wenn ein Style Plugin geladen wird das versucht mit CE_RubberBand diesen zu bearbeiten. OpenSuSE hatte bei KDE4.1 hier mal einen Bug produziert weshalb ich das immer noch drinne habe.
Wenn man den Style an dieser Stelle ändern möchte geht das nur in dem man ein Style Plugin hinzu lädt - dies wird unter QStyleOption beschrieben.

melanie
15-09-2010, 14:31
Hallo,
ich muss diesen Thread leider nochmal aufrollen... Mit dem QRubberBand komme ich gut klar (ich habe das mit der Farbe nicht hinbekommen, aber es geht auch so).
Jetzt habe ich allerdings eine andere Aufgabenstellung. Ich müsste nun Dreiecke zeichnen. Ich würde das denke ich gerne mit QPainter machen und dann drawPolygon().
Aus der Dokumentation habe ich folgendes Beispiel:

static const QPointF points[3] = {
QPointF(10.0, 80.0),
QPointF(20.0, 10.0),
QPointF(80.0, 30.0),
};

QPainter painter(this);
painter.drawPolyline(points, 3);

Eingebaut in mein "altes Minimalprogramm" habe ich dann diesen Quellcode:

MainWindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <Qt/QMainWindow.h>
#include "Forms/Ui_MainWindow.h"

class QAction;
class QLabel;
class QMenu;

class MainWindow : public QMainWindow, protected Ui_MainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = 0);

private:
QImage GenerateQImage(int value);
QLabel *imageLabel;
};

#endif

MainWindow.cpp:

#include <Qt/QLabel.h>
#include <QtGui/QtGui>
#include "MainWindow.h"

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
setupUi(this);
imageLabel = new QLabel(this->centralWidget()); //platziert das Label auf dem Fenster
imageLabel->setBackgroundRole(QPalette::Base);
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
imageLabel->setScaledContents(true);

//Startbild generieren
QImage image = GenerateQImage(255);
imageLabel->setPixmap(QPixmap::fromImage(image));
imageLabel->setVisible(true);

static const QPointF points[3] = {
QPointF(10.0, 80.0),
QPointF(20.0, 10.0),
QPointF(80.0, 30.0),
};

QPainter painter(imageLabel);
painter.drawPolyline(points, 3);

connect(action_Beenden, SIGNAL(triggered()), this, SLOT(close()));
}

QImage MainWindow::GenerateQImage(int value)
{
QImage img_gray(200, 200, QImage::Format_Indexed8);
// Colortable erstellen für Graustufen
QVector<QRgb> grayscales;
for (int i=0; i<256; ++i)
grayscales.push_back(qRgb(i,i,i));
// colortable dem graustufen bild zuweisen
img_gray.setColorTable(grayscales);

for (int z=0; z<200; ++z)
for (int x=0; x<200; ++x)
{
img_gray.setPixel(x,z, value);
}
return img_gray;
}

Irgendwas stimmt natürlich nicht :confused: allerdings habe ich nur Anleitungen mit paintEvent gefunden (die ich auch nicht wirklich verstanden habe). Kann mir jemand helfen :o

Die Fehlermeldung, die angezeigt wird lautet übrigens: QPainter::begin: Paint device returned engine == 0, type: 1

locus vivendi
15-09-2010, 16:44
Du darfst nicht ausserhalb eines Paintevent auf ein Widget zeichnen. Das geht nur mit einer speziellen Option, und auch dann nur auf X-Windows. Also nicht Windows oder Mac. Siehe dazu QPainter-Doku bzw. QWidget:: paintEvent. Das sollte es eigentlich schon sein. Wenn nach umschreiben die Fehlermeldung immer noch kommt, melde dich nochmal.

melanie
17-09-2010, 14:29
Hallo,
ich habe ein bisschen rumgetüftelt und habe jetzt genau das Problem, das ich schon kommen gesehen habe :) Es wird gezeichnet, aber immer. Ich hätte gerne, dass auf ein Bild, welches auf dem Label dargestellt wird, gezeichnet wird, wenn ich z.B. einen Button drücke (der z.B. den SLOT zeichnen() auslöst) und das die Zeichnung wieder verschwindet, wenn ich das Bild auf das Label neu zeichne.
Hier mal mein ergänzender Quellcode

Änderung in MainWindow.cpp:

imageLabel = new MyLabel(this->centralWidget());

Neu -> MyLabel.h:

#ifndef MYLABEL_H
#define MYLABEL_H

#include <Qt/QLabel.h>
//#include <Qt/QMainWindow.h>

class MyLabel: public QLabel
{
Q_OBJECT

//signals:

public:
MyLabel(QWidget * parent = 0, Qt::WindowFlags f = 0);

protected:
void paintEvent(QPaintEvent *event);

};

#endif //MYLABEL

Neu -> MyLabel.cpp:

#include "MyLabel.h"
#include <QtGui/QMouseEvent>
#include <QtGui/QtGui>


MyLabel::MyLabel(QWidget * parent, Qt::WindowFlags f):
QLabel(parent, f)
{}

void MyLabel::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
static const QPointF points[3] = {
QPointF(10.0, 80.0),
QPointF(20.0, 10.0),
QPointF(80.0, 30.0),
};

painter.drawPolygon(points, 3);

}

Für jede Hilfe bin ich sehr dankbar!

anda_skoa
17-09-2010, 16:13
Wenn du den den Inhalt des QLabel haben willst, einfach an dessen paintEvent() Method delegieren.

z.B:



void MyLabel::paintEvent(QPaintEvent *event)
{
// zuerst den eigentlichen Labelinhalt zeichen
QLabel::paintEvent(event);

// dann darauf das eigene
QPainter painter(this);
static const QPointF points[3] = {
QPointF(10.0, 80.0),
QPointF(20.0, 10.0),
QPointF(80.0, 30.0),
};

painter.drawPolygon(points, 3);
}


Ciao,
_

melanie
20-09-2010, 07:31
Hallo,

ich habe es leider immer noch nicht verstanden... Wenn ich es so mache, wie anda_skoa vorschlägt, dann zeichne ich doch immer das Dreieck. Ich möchte aber nur einmal kurz (nach einem Button-Klick z.B.) das Dreieck zeichnen und während der sonstigen Programmlaufzeit gar nicht. Geht das nicht?

locus vivendi
20-09-2010, 11:01
Möchtest du
a) Das Dreieck anzeigen nachdem der Benutzer auf einen Button geklickt, solange bis der Button nochmal geklickt wird
oder
b) Nach einem Klick für eine bestimmte Zeit anzeigen, und dann automatisch verschwinden lassen?

Um Alternative a zu implementieren kannst du z.B.
1. Einen QPushbutton anlegen
2. Den Button "checkable" machen
3. Einen Slot in deiner Klasse anlegen, der ein Repaint auslöst.
4. Das "clicked(bool)" Signal des Buttons mit deinem Slot verbinden.
5. In der überschriebenen paintEvent-Funktion abfragen in welchem Zustand sich der Button befindet.
6. Davon abhängig das Dreieck zeichnen oder nicht.

Für Alternative b:
Bei klicken des Buttons (der dann nicht "checkable" sein sollte) irgendeinen Timer starten, das Dreieck zeichnen und bei "feuern" des Timers das Dreieck verschwinden lassen.

melanie
20-09-2010, 15:09
Hallo locus vivendi,
ich habe schon befürchtet, dass ich es so in der Art machen muss. Danke für den Tipp. Ich werde mich mal dransetzen und mein Glück versuchen!

melanie
20-09-2010, 16:31
Mhh, was ich jetzt noch nicht verstehe: Mein paintEvent verändere ich in der MyLabel Klasse, den Menü-Button (checkable) binde ich aber in meiner MainWindow Klasse ein. Wie kann ich jetzt auf den Wert von dem Button in der MyLabel Klasse zugreifen. Vielleicht stehe ich auch total auf dem Schlauch :rolleyes:

anda_skoa
21-09-2010, 12:22
Eine Möglichkeit ist, in MyLabel einen Slot zu machen und den mit dem Button zu verbinden.

Hat den Vorteil, dass du ein Update des Labels anfordern kannst



class MyLabel : public QLabel
{
Q_OBJECT

//...

public Q_SLOTS:
void toggleOverlay( bool on );

private:
bool mShowOverlay;
};




void MyLabel::toggleOverlay( bool on )
{
if ( on != mShowOverlay ) {
mShowOverlay = on;
update();
}
}


Ciao,
_

melanie
21-09-2010, 17:15
Hallo anda_skoa,

vielen Dank für die tolle Idee. Konnte es umsetzen.

Für mein Programm wäre es sinnvoll, wenn ich die Koordinaten des Dreieckes im Hauptprogramm festlegen könnte. Hat jemand von euch eine Idee, wie ich die Koordinaten aus MainWindow.cpp zeitgleich mit dem bool-Wert, der kennzeichnet, dass gezeichnet werden kann, in MyLabel.cpp schubsen kann? Signals und Slots kann ich - soweit ich durchblicke - ja wohl nur für QObject Klassen verwenden und das ist ein QPointF Array ja nicht.

locus vivendi
21-09-2010, 19:01
[...]
Signals und Slots kann ich - soweit ich durchblicke - ja wohl nur für QObject Klassen verwenden und das ist ein QPointF Array ja nicht.
Aber du kannst ein QPointF-Objekte durchaus über eine Signal-Slotverbindung senden.


public Q_SLOTS:
void xyz(QPointF p) { ... }

melanie
22-09-2010, 09:19
Hallo :),

wie sieht denn dann das Signal aus? Ich hatte mir sowas in der Art überlegt:

MainWindow.h

class MainWindow : public QMainWindow, protected Ui_MainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = 0);

private:
QImage GenerateQImage(int value);

void setPoints();

MyLabel *imageLabel;
QPointF *p_pts;

signals:
void pointsChanged(QPointF *new_p_pts);

};

MainWindow.cpp

...
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
...
setPoints();
connect(action_Beenden, SIGNAL(triggered()), this, SLOT(close()));
connect(WAS MUSS HIER HIN???, SIGNAL(pointsChanged(QPointF *)), imageLabel, SLOT(setPointArray(QPointF *)));
connect(actionAnzeigen, SIGNAL(triggered(bool)), imageLabel, SLOT(toggleOverlay(bool)));
}

void MainWindow::setPoints()
{
QPointF pts[3] = {
QPointF(10.0, 80.0),
QPointF(20.0, 10.0),
QPointF(80.0, 30.0),
};

if(&pts[0] != p_pts)
{
p_pts = pts;
emit pointsChanged(p_pts);
}
}


Und in der MyLabel Klasse

MyLabel.h

class MyLabel: public QLabel
{
Q_OBJECT

//signals:

public:
MyLabel(QWidget * parent = 0, Qt::WindowFlags f = 0);

protected:
void paintEvent(QPaintEvent *event);

public Q_SLOTS:
void toggleOverlay(bool on);
void setPointArray(QPointF *pts);

private:
bool mShowOverlay;
QPointF *points;

};


MyLabel.cpp

...
void MyLabel::setPointArray(QPointF *pts)
{
points = pts;
}

Ich bin mir aber nicht sicher, ob das der richtige Weg ist und wie gesagt weiß ich nicht, wer der Sender des Signals sein muss...

locus vivendi
22-09-2010, 11:30
Wenn du nur einen Zeiger auf die Punkte speicherst wirst du unter Umständen Speicherfehler bekommen. So wie der Code in deinem letzten Post steht, sogar ganz bestimmt.

Ich habe mal zwei Dateien angehängt, als kleines Beispiel wie du die Verbindung zwischen Label und Mainwindow herstellen kannst.

Erst "moc -o xw.moc.cc xw.hh" aufrufen. Dann xw.cc kompilieren. Die Ausgabe von moc wird in xw.cc unten eingebunden, es ist also nicht notwendig noch irgendwelche .o-Dateien einzubinden.

Okay... Dateien anhängen geht aus irgendeinem Grund nicht, also hier direkt:
xw.hh:


#ifndef XW_HH
#define XW_HH

#include "QtCore/QObject"
#include "QtCore/QPointF"
#include "QtGui/QApplication"
#include "QtGui/QColor"
#include "QtGui/QHBoxLayout"
#include "QtGui/QPainter"
#include "QtGui/QPen"
#include "QtGui/QPushButton"
#include "QtGui/QWidget"

class X : public QWidget // Dies ist die "Label"-Klasse, welche das Dreieck anzeigt.
{
Q_OBJECT

public:
X(QWidget* parent) : QWidget(parent), do_highlight(false)
{
setMinimumSize(400, 300);
setAutoFillBackground(true);
}

public Q_SLOTS:
void highlight(bool yes_or_no, QPointF a, QPointF b, QPointF c)
{
do_highlight = yes_or_no;
points[0] = a; points[1] = b; points[2] = c;
update();
}

protected:
virtual void paintEvent(QPaintEvent*)
{
if(do_highlight) {
QPainter painter(this);
QPen pen(QColor(255, 0, 0));
pen.setWidth(3);
painter.setPen(pen);
painter.drawConvexPolygon(points, 3);
}
}

private:
bool do_highlight;
QPointF points[3];
};

class W : public QWidget // Dies ist die "Mainwindow"-Klasse.
{
Q_OBJECT

public:
W() : layout(this), show_button("Press!", this), exit_button("Exit!", this), triangle(this)
{
setLayout(&layout);
layout.addWidget(&show_button);
layout.addWidget(&exit_button);
layout.addWidget(&triangle);
show_button.setCheckable(true); // Die letzten fünf Zeilen waren Vorarbeiten..
QObject::connect(&show_button, SIGNAL(clicked(bool)), this, SLOT(button_clicked(bool))); // Interne Verbindung.
QObject::connect(&exit_button, SIGNAL(pressed()), QApplication::instance(), SLOT(quit())); // Beendet Programm auf Klick.
QObject::connect(this, SIGNAL(have_points(bool, QPointF, QPointF, QPointF)), &triangle, SLOT(highlight(bool, QPointF, QPointF, QPointF)));
// Die letzte Zeile verbindet die beiden Klassen miteinander.
}

Q_SIGNALS:
void have_points(bool yes_or_no, QPointF a, QPointF b, QPointF c); // Dieses ist das Signal welches die beiden Klassen verbindet.

private Q_SLOTS:
void button_clicked(bool checked) { // Dies ist ein "interner" Slot.
QPointF p1(10.0, 10.0), p2(100.0, 100.0), p3(190.0, 10.0); // Diese Punkte dienen nur als Beispiel.
// Folgende Zeile ist die "Magie": Hier wird das clicked()-Signal des Pushbuttons auf die richige Signatur erweitert.
Q_EMIT have_points(checked, p1, p2, p3);
// Der Pushbutton löst also indirekt have_points(bool, QPointF, QPointF, QPointF) aus.
}

private:
QHBoxLayout layout;
QPushButton show_button, exit_button;
X triangle;
};

#endif

xw.cc:


#include "xw.hh"

int main(int argc, char* argv[])
{
QApplication app(argc, argv);
W w;
w.show();
return app.exec();
}

#include "xw.moc.cc"

anda_skoa
22-09-2010, 11:32
Der erste Parameter im connect ist immer der Sender.
D.h. eine Instanz der Klasse, die das Signal anbietet. In deinem Fall also "this".

An irgendeiner Stelle in deinem Mainwindow, wenn du eben neue Punkte haben willst, machst du dann



emit pointsChanged( p_pts );

Also das Signal mit aktuellen Werten aussenden.

Was du allerdings ändern solltest, ist den Signalparametertyp.
Pointer sind nicht sehr gut, weil man dann leicht vergisst, wer der "Besitzer" ist (also wer den Pointer löschen muss).

Mein Vorschlag wäre QVector, also



// ....

QVector<QPointF> p_pts;

signals:
void pointsChanged( QVector<QPointF> new_p_pts );


QVector hat hier zusätzlich den Vorteil, dass du eine sichere Länge hast, die du abfragen kannst.

Ciao,
_