Slot in Slot auslösen

Alles rund um die Programmierung mit Qt
kannaum
Beiträge: 73
Registriert: 31. Januar 2010 09:57

Slot in Slot auslösen

Beitrag von kannaum »

Hi,

Ich habe folgendes Problem:

Ich habe ein Main Window.
Darin sind 4 Buttons, wo durch einen Klick jeweils ein Slot ausgelöst wird.

In diesem Slot habe ich 4Labels und 4 Buttons, die dann, wenn auf die Buttons geklcikt wurde, angezeigt werden.
Das geht ja auch alles.
Nun möchte ich aber "innerhalb" des Slots auch noch die Buttons mit Slots verbinden. Dieser Slot soll dann einen Dialog öffnen, zum Auswählen eines Fotos öffnen, welches dann in einem Qpixmap gespeichert wird und einem Label zugewiesen wird.
Das ganze geht aber leider nciht.
Folgende Fehlermeldungen:
1. invalid use of "this" in non-member function
2. l_bild1 was not declared in this scope

Hoffe das war einigermaßen verständlich erklärt.

Jetzt noch die wichtigsten Passagen in meinem kleinen Code:

Code: Alles auswählen

//Die 4 Buttons die am Anfang da sind mit den Signal and Slots
    auswahl1 = new QPushButton("2 Bilder");
    auswahl2 = new QPushButton("3 Bilder");
    auswahl3 = new QPushButton("4 Bilder");
    auswahl4 = new QPushButton("5 Bilder");

    connect(auswahl1, SIGNAL(clicked()), this, SLOT(f_auswahl1()));
    connect(auswahl2, SIGNAL(clicked()), this, SLOT(f_auswahl2()));
    connect(auswahl3, SIGNAL(clicked()), this, SLOT(f_auswahl3()));
    connect(auswahl4, SIGNAL(clicked()), this, SLOT(f_auswahl4()));
//Layout etc.
    QWidget *auswahl = new QWidget;

    auswahl_layout = new QHBoxLayout;
    auswahl_layout->addWidget(auswahl1);
    auswahl_layout->addWidget(auswahl2);
    auswahl_layout->addWidget(auswahl3);
    auswahl_layout->addWidget(auswahl4);

    auswahl->setLayout(auswahl_layout);
    setCentralWidget(auswahl);

Code: Alles auswählen

void MainWindow::f_auswahl1() {
    layout = new QGridLayout;
    bilder = new QWidget;
    l_bild1 = new QLabel("Bild 1");
    l_bild2 = new QLabel("Bild 2");
    l_bild3 = new QLabel("Bild 3");
    l_bild4 = new QLabel("Bild 4");

    b_auswahl1 = new QPushButton("");
    b_auswahl2 = new QPushButton("");
    b_auswahl3 = new QPushButton("");
    b_auswahl4 = new QPushButton("");
    connect(b_auswahl1, SIGNAL(clicked()), this, SLOT(bild_auswerten1()));
    layout->addWidget(b_auswahl1, 0, 0);
    layout->addWidget(b_auswahl2, 0, 1);
    layout->addWidget(l_bild1, 1, 0, 3, 1);
    layout->addWidget(l_bild2, 1, 1, 3, 1);
    bilder->setLayout(layout);
    setCentralWidget(bilder);
}

Code: Alles auswählen

void bild_auswerten1() {
    QString fileName = QFileDialog::getOpenFileName(this, "Open Image", "/home/jana", "Image Files (*.png *.jpg *.bmp)");
    QPixmap *foto = new QPixmap(fileName);
    l_bild1->setPixmap(foto);
}
mfg
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Vielleicht solltest du auch einfach anstelle "void bild_auswerten1()" eher "void MainWindow::bild_auswerten1()" schreiben...

dann klappts auch mit "this" und "l_bild1" wieder.

hth..


[EDIT]
Dafür klappts dann mit "setPixmap(....)" nicht mehr, aber das findest du dann schon selbst raus :wink:
Zuletzt geändert von solarix am 15. Oktober 2010 17:36, insgesamt 1-mal geändert.
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

Das sieht bisserl abstrus aus, du ersetzt in nem Slot die Oberfläche deines MainWidgets durch ne Neue, das Alte wird dabei einfach untern Tisch gekehrt ... . Das was du m.E. suchst ist ein QDialog.

Gui->4 Knöpfe->jeder startet ein QDialog mit wieder je 4 Knöpfen ...

Sag mal was du machen willst, nicht wie du denkst es realisieren zu können :)
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
kannaum
Beiträge: 73
Registriert: 31. Januar 2010 09:57

Beitrag von kannaum »

Ok mein Programm sollte am Anfang folgendes machen:

Wenn man es öffnet kommen 4 Buttons mit der Beschriftung 2 Bilder, 3 Bilder etc.

Wenn man dann auf einen draufklickt sollen die 4 Buttons verschwinden und es sollen 2,3 etc. Buttons und Labels angezeigt werden.

Durch einen Klick auf einen Button wird ein Dateidialog gestartet und das ausgewählte Bild wird in das Label unter dem Button geöffnet.

mfg
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

Das geht zB so:

Code: Alles auswählen

#ifndef ICONWIDGET_H
#define ICONWIDGET_H

#include <QtGui/QFrame>
#include <QtGui/QVBoxLayout>
#include <QtGui/QHBoxLayout>
#include <QtGui/QScrollArea>
#include <QtGui/QPushButton>
#include <QtGui/QLabel>
#include <QtGui/QFileDialog>
#include <QtGui/QImageReader>
#include <QtGui/QInputDialog>
#include <QtGui/QImage>

class ImageChooser : public QFrame
{
    Q_OBJECT
    
public:
    
    explicit ImageChooser(QWidget *parent = 0) : QFrame(parent)
    {
        setFrameStyle(QFrame::Raised|QFrame::Panel);
        QVBoxLayout * lay = new QVBoxLayout(this);
        button = new QPushButton("Bild laden...", this);
        area = new QScrollArea(this);
        
        lay->addWidget(button);
        lay->addWidget(area);
        setMinimumSize(100,80);
        
        connect(button,SIGNAL(clicked()),this,SLOT(loadImage()));
    }
    
private slots:
    
    void loadImage()
    {
        QStringList formats; // speichere alle Formate
        {

            QList<QByteArray> imageFormats = QImageReader::supportedImageFormats(); // erstmal alle holen
            foreach (QByteArray a, imageFormats)
                formats << QString(a).prepend("*."); // mit *. davor in die Liste
        }
        
        QString pfad = QFileDialog::getOpenFileName(this,
                                                    "Bild laden ...",
                                                    QDir::homePath(),
                                                    formats.join(" ").append(")").prepend("Bilder (")); // pack "Bilder (" davor und ")" dahinter, ansonsten trenne die mit " "
        
        if (pfad.isNull()) return; // keins ausgewählt (die Auswahl gibts übrigens auch gleich für mehrere Datein, dann würde das ganze drumrum entfallen ;)
        
        label = new QLabel; // mach mir ein neues Label
        QImage img(pfad); // lade Bild
        label->setPixmap(QPixmap::fromImage(img)); // packs ins label
        // alternativ so, das skaliert deine Bilder vorher etwas runter
        // label->setPixmap(QPixmap::fromImage(img.scaled(250,200,Qt::KeepAspectRatio))); 

        area->setBackgroundRole(QPalette::Dark); 
        area->setWidget(label); // lass das QScrollArea es verwalten
        


        button->close(); // den brauch mer nimmer, weg damit
    }
    
private:
    QPushButton * button;
    QScrollArea * area;
    QLabel * label ;
};

Code: Alles auswählen

class IconWidget : public QWidget
{
    Q_OBJECT
    
public:
    explicit IconWidget(QWidget *parent = 0) : QWidget(parent)
    {
        QHBoxLayout * lay = new QHBoxLayout(this);
        
        int anzahl = QInputDialog::getInt(0,"Wieviele Bilder sollens werden?","Anzahl Bilder:",2,2,10,1);
        
        for(int i=0;i< anzahl; ++i)
        {
            // bau mir genügend neben einander
            ImageChooser * ic = new ImageChooser(this);
            lay->addWidget(ic);
        }
    }
};
#endif // ICONWIDGET_H

Insgesamt ein wenig Seltsam :) aber bitte.

Ich hab deine "Spezifikation" sinnvoll aufgeteilt. Du willst den Benutzer bestimmen lassen wieviele Bilder er darstellen will, dann sollen entsprechend viele Bilder je per Knopf geladen werden.

Knopf und Bild laden ist eine (logische) Einheit, das ist bei mir in die Klasse ImageChooser gewandert. Das ist im wesenlichen ein QWidget mit ein bisschen Randmalerei (==QFrame) das einen Knopf und ein QLabel fürs Bild besitzt. Da Bilder oft groß sind, hab ich das Label in ein QScrollWidget gepackt was bei Bedarf entsprechende Scrollbars anzeigt. Das schöne an solch einer Auftelung ist das du dort einmal die Slots/Signals/Connects machst und dann einfach benutzen kannst ohne im Hauptprogramm (das die Anzahl der Bilder abfragt) daran denken zu müssen ...

Der Knopf ist mit dem Slot verbunden, im Slot wird ein Dateiname abgefragt, ist der leer dann passiert nix. Ist er ok wird das Label erstellt, das Bild reingepackt und der Knopf zerstört.

Das IconWidget fragt beim Start den Benutzer nach einer Anzahl (QInputDialogs sind praktischer als Buttons, IMHO). Die Anzahl wird genutzt um eine entsprechende Anzahl an ImageChooser Widgets in das HLayout zu packen ... 2-10 hab ich als willkürliche Grenze des QInputDialogs gesetzt.
Zuletzt geändert von padreigh am 16. Oktober 2010 12:26, insgesamt 3-mal geändert.
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
kannaum
Beiträge: 73
Registriert: 31. Januar 2010 09:57

Beitrag von kannaum »

Ok vielen, vielen Dank.
Verstehe die Logik da hinter größtenteils.

Könntest du mir bitte noch ein Praxis-Beispiel damit zeigen??

Habe nämlich so etwas noch nie gesehen, geeschweige denn gemacht.

mfg
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

Praxisbeispiel? Du kopierst alles zusammen in ein .h, nimmst ein .cpp das dieses .h includiert und benutzt es:

iconwidget.h

Code: Alles auswählen

// siehe oben, had noch bisserl text reineditiert ...
iconwidget.cpp

Code: Alles auswählen

#include "iconwidget.h"
main.cpp

Code: Alles auswählen

#include <QApplication>
#include "iconwidget.h"

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

Code: Alles auswählen

TARGET = IconWidget
TEMPLATE = app
HEADERS =  iconwidget.h
RESOURCES = main.cpp iconwidget.cpp
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
kannaum
Beiträge: 73
Registriert: 31. Januar 2010 09:57

Beitrag von kannaum »

@padreigh:
Hast du meine Pn bekommen?
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

Ups, sorry, meine PMs guck ich nicht an, helfen tu ich gerne in (neuen) Threads im Forum ... dann haben alle was davon...

PM (Fragen zu Zoom verwirklichung):
Habe 2 einfache Buttons einmal für hinein und einmal für hinauszoomen gemacht:

Code: Alles auswählen

        zoom_in = new QPushButton("+");
        zoom_out = new QPushButton("-");
        connect(zoom_in,SIGNAL(clicked()),this,SLOT(f_zoom_in()));
        connect(zoom_out,SIGNAL(clicked()),this,SLOT(f_zoom_out()));
Ein SLOT sieht folgendermaßen aus:
Code:

Code: Alles auswählen

    void f_zoom_in() {
        int w = img->width();
        int h = img->height();
        w *= 1.1;
        h *= 1.1;
        QImage newimg = img->scaled(w, h);
        label->clear();
        label->setPixmap(QPixmap::fromImage(newimg));
    }

Leider geht das nicht, da ich anscheinend vom SLOT heraus nicht auf das Bild zugreifen kann.
Die Klasse ImageChooser wird gerade mehr zum ImageDisplayer :D

Ich glaube, du solltest dir Klassen/public/protected/private-Konzepte nochmal anschaun ... du brauchst kein public-image ... du brauchst eine public methode zum Zoomen. Wenn du mehrmals hin und herzoomst (0.75, 2.3, 0.66, 1.87, 0.1, 20) wird dein Bild immer schlechter so wie du das vorhast ... änder lieber den ImageChooser so ab, das er das original geladene Bild als privaten member speichert (m_image), bastel eine private Methode die den Zoom in begrenzten Bereich durchführt. Dann spendierst du dem Benutzer eine/mehrere public Methoden die den Zoom verändern:

Code: Alles auswählen

class ImageChooser : public QFrame
{
// alles wie gehabt
// im Konstruktor m_zoom auf 1.0 setzen
//  in loadImage() statt  "QImage img(pfad);" m_image.load(pfad); 

public slots:
    void resetZoom()                      {   updateZoomedImage( 1.0 );   }
    void zoomIn()                           {   updateZoomedImage( m_zoom + 0.1 );   }
    void zoomOut()                         {   updateZoomedImage( m_zoom - 0.1 );    }
    void zoomImage(qreal zoom)     {   updateZoomedImage(zoom);    }

private slots:
   void updateZoomedImage(qreal zoom)
   {
        // zomen nur im Bereich 10% bis 1000% erlaubt
        // wenn der Zoom schon da ist, mach nix
        if ( (zoom < 0.1 || zoom > 10) || 
           (zoom = m_zoom)) return;

        m_zoom = zoom;
        QSize wantedSize = m_image.size(); // original size
        wantedSize *= zoom;  // gewünschte Größe
        label->setPixmap(QPixmap::fromImage(m_image.scaled(wantedSize,Qt::KeepAspectRatio)));
    }
   
private:
    qreal m_zoom;
    QImage m_image;
};
( Hab den code nur runtergetippt, sollte aber so ungefähr tun) Achja, du könntest dir mal QToolButtons anschaun, die sind für so +- Button m.E. besser :) oder gleich ne Lupe zeichnen und ein +- rein machen und ein Icon nehmen :)
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
kannaum
Beiträge: 73
Registriert: 31. Januar 2010 09:57

Beitrag von kannaum »

Ok, danke im Nachhinein kommt ihm einen der Code eh selbstverständlich vor ;-)

Leider geht es aber noch immer nicht.
Ich bekomme auch keine Fehlermeldung und auch sonst ist alles normal.

Um gleich mal einen Fehler von mir auszuschließen, oder eben auf die Schliche zu kommen:
Den Konstuktor habe ich um folgendes erweitert:

Code: Alles auswählen

m_zoom = 1.0;
Bei loadImage habe ich folgendes geändert:

Code: Alles auswählen

m_image.load(pfad);  // lade Bild
label->setPixmap(QPixmap::fromImage(m_image)); // packs ins label
Bei den private slots habe ich dann auch noch updateZoomendImage reikopiert und bei den public slots folgendes reinkopiert:

Code: Alles auswählen

void resetZoom()                      {   updateZoomedImage( 1.0 );   }
    void zoomIn()                           {   updateZoomedImage( m_zoom + 0.1 );   }
    void zoomOut()                         {   updateZoomedImage( m_zoom - 0.1 );    }
    void zoomImage(qreal zoom)     {   updateZoomedImage(zoom);    }



mfg
[/code]
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

es fehlte ein = ...

Code: Alles auswählen

void updateZoomedImage(qreal zoom)
    {
        qDebug() << "zoom: " << zoom;

         // zomen nur im Bereich 10% bis 1000% erlaubt
         // wenn der Zoom schon da ist, mach nix
         if ( (zoom < 0.1 || zoom > 10) ||
            (zoom == m_zoom)) return;  // und zwar hier

         m_zoom = zoom;
         QSize wantedSize = m_image.size(); // original size
         wantedSize *= zoom;  // gewünschte Größe
         label->setPixmap(QPixmap::fromImage(m_image.scaled(wantedSize,Qt::KeepAspectRatio)));
         label->resize(label->sizeHint());
         qDebug() << "size now: " << wantedSize;
     }
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
kannaum
Beiträge: 73
Registriert: 31. Januar 2010 09:57

Beitrag von kannaum »

Ok danke und gibt es auch eine Möglichkeit das Bild nur zu vergrößern, sodass man danach auch noch herumscrollen kann?
Hätte schon in der Doku bei QPixmap geschaut, habe aber nichts passendes gefunden.

mfg
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

detr weg ist: pfad zum bild ermitteln -> originalbild laden -> originabild scalen und von der gescalten pixmap von machen -> pixmap auf label pappen -> label auf größe des neuen pixmap resizen und von scrollarea verwalten lassen ...

Was und wie du scalest bestimmst du selbst durch deine + und - Knöpfe (oder meinetwegen durch ne qdoublespinbox) und entsprechende connects. Läßt du kein - zu, mach setEnabled(false) auf die entsprechenden Knöpfe ?

Du kannst fürs Vergrößern auch verschiedene Methoden an scale üübergeben ... siehe API QImage::scale()
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
kannaum
Beiträge: 73
Registriert: 31. Januar 2010 09:57

Beitrag von kannaum »

Danke, habe deine Funktion wie folgt umgewandelt:

Code: Alles auswählen

void updateZoomedImage(qreal zoom)
       {
            // zomen nur im Bereich 10% bis 1000% erlaubt
            // wenn der Zoom schon da ist, mach nix
            if ( (zoom < 0.1 || zoom > 10) ||
               (zoom == m_zoom)) return;

            m_zoom = zoom;
            image.load(pfad);
            QSize wantedSize = image.size(); // original size
            wantedSize *= zoom;  // gewünschte Größe
            label->setPixmap(QPixmap::fromImage(image.scaled(wantedSize,Qt::KeepAspectRatioByExpanding)));
        }
Ich vergrößere nun ja immer das Originalbild, wie du es gesagt hast.
Leider hat sich jetzt gar nichts geändert.
Wollte mir auch zu meinen eigenen besseren Verständnis mal m_zoom ausgeben lassen, wusste aber wegen dem Datentype qreal nicht so recht wie.

Habe inzwischen schon das Programm zu einem MainWindow gemacht und auch schon eine "Screenshot-FUnktion" gemacht.
Funktioniert beides so wie ich will.

Über einen Menüpunkt soll auch ein Dialog für Einstellungen geöffnet werden.
Das ganze hätte ich so gemacht:

Code: Alles auswählen

//Bei public:
Dialog *dialog;

//Menüpunkt
M_datei->addAction(QIcon("led-icons/cog.png"),tr("&Einstellungen..."), this, SLOT(settings()));

//Slot: settings()
 void settings() {
        dialog = new Dialog;
    }

//KLasse Dialog
class Dialog : public QDialog {
    Q_OBJECT
public:
    explicit Dialog(QMainWindow *parent = 0) {
        QTabWidget *tab = new QTabWidget(this);
        QWidget *screenshot = new QWidget(this);
        QGridLayout *screenshotLay = new QGridLayout(this);
        QLabel *screenLab = new QLabel("Speicherort für die Screenshots: ", this);
        QLineEdit *screenBut = new QLineEdit("D:/", this);
        QLabel *screenLab2 = new QLabel("Format für die Screenshots: ", this);
        QComboBox *screenComb = new QComboBox(this);
        screenComb->addItem(".jpg");
        screenComb->addItem(".png");
        screenComb->addItem(".gif");
        screenComb->addItem(".bmp");
        screenshotLay->addWidget(screenLab, 0, 0);
        screenshotLay->addWidget(screenBut, 1, 0);
        screenshotLay->addWidget(screenLab2, 2, 0);
        screenshotLay->addWidget(screenComb, 3, 0);
        tab->addTab(screenshot, QIcon("led-icons/camera.png"), "Screenshot");
        screenshot->setLayout(screenshotLay);
    }

};
Wenn ich dann auf den Menüpunkt klicke tut sich gar nichts.

Und ich weiß, dass der Einstellungsdialog noch ncihts bringt, aber das mach ich dann schon noch wenn ich mal den Dialog sehe :lol:

mfg
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

qreal ist einfach ein typedef für double(meist) / float(selten) http://doc.trolltech.com/4.6/qtglobal.html .. also ne Kommazahl. Gewöhn dir #include <QDebug> an ... und nutze qDebug() << irgendsonqtzeug; damit ... der kann viel Ausgeben.

dann guck doch einfach mal bei QDialog, klick da auf "Mehr ..." und lies bis du zu den Beispielen kommst .. dann verleich deins mit den Beispielen und du siehst was dir fehlt... und wenn du jetzt nochmal genau mein letzten codepost mit deinem letzten vergleichst geht dir vielleicht noch ein Licht auf warum dein Label ich nicht ändert, meins aber doch :P

zum Abspeichern leg ich dir mal http://doc.qt.nokia.com/4.6/qfiledialog ... veFileName ans Herz, das macht dein Tab fast überlüssig ... ein Knopf + Slot reicht.
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
Gesperrt