QGridLayout

Alles rund um die Programmierung mit Qt
Antworten
ghostboss
Beiträge: 28
Registriert: 25. September 2010 17:10

QGridLayout

Beitrag von ghostboss »

Hallo,

1.

wenn ich Widgets in QGridLayout adde dann wird der Inhalt immer zentriert.

Code: Alles auswählen

ein Element
 ----------- 
|              |
|              |
| text text |
|              |
|              |
 -----------

zwei Elemente
 ----------- 
|              |
| text text |
|              |
| text text |
|              |
 -----------

ich will das aber so
 ----------- 
| text text |
| text text |
|              |
|              |
|              |
 -----------
Wie kann ich das ändertn?
Mein Code:

Code: Alles auswählen

#include "HtmlAttributes.h"

#include <QMessageBox>

HtmlAttributes::HtmlAttributes(QWidget *parent) : QWidget(parent){
    layoutGrid = new QGridLayout;
}

void HtmlAttributes::createAttirbutes(QWebElement *web_element, QList<QString> html_attributes){

    for(qint32 i=0; i < labels.size(); ++i){
        QLabel* label = labels.at(i);
        delete label;
        labels.removeAt(i);
        --i;
    }

    for(qint32 i=0; i < lineEdits.size(); ++i){
        QLineEdit* lineEdit = lineEdits.at(i);
        delete lineEdit;
        lineEdits.removeAt(i);
        --i;
    }

    for(qint32 i=0; i < html_attributes.size(); ++i){
        QString attributeName = html_attributes.at(i);
        QString attributeValue = web_element->attribute(attributeName, "-");

        QLabel* label = new QLabel(attributeName);
        QLineEdit* lineEdit = new QLineEdit(attributeValue);

        layoutGrid->setRowMinimumHeight(i, 0);
        layoutGrid->addWidget(label, i, 0);
        layoutGrid->addWidget(lineEdit, i, 1);

        labels.push_back(label);
        lineEdits.push_back(lineEdit);
    }
    setLayout(layoutGrid);
//QMessageBox::information(this, "test", QVariant(layoutGrid->verticalSpacing()).toString(), QMessageBox::Ok);
}
2.
Kann man den Rahmen von QGridLayout anzeigen?
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

pack das Grid in ein QVBoxLayout und nutze da addStretch, oder pack gleich deine Texte in ein QVBoxLayout ohne das Grid.

Alternativ versuch mal: setRowStretch ( 2, 1 ); // row 2 ist zwar leer aber ....
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
ghostboss
Beiträge: 28
Registriert: 25. September 2010 17:10

Beitrag von ghostboss »

Hab das jetzt mit

Code: Alles auswählen

layoutGrid->setAlignment(Qt::AlignTop)
gemacht.

Was mich noch interesiert ist ob was im speicher bleibt, weil ich die Funktion sher oft aufruffe? Die Labels und LineEdits werden ja mit delete gelöscht, aber was ist mit den QGridLayout, soll ich den auch deleten und dan neu erstellen?
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

*graus* hab garnicht auf den Code geachtet ---
mit delete gelöscht ... rufe ich sehr oft auf ...

Code: Alles auswählen

    
for(qint32 i=0; i < labels.size(); ++i){
        QLabel* label = labels.at(i);
        delete label;
        labels.removeAt(i);
        --i;
    } 


Was ein Hack ... wie wäre es mit qDeleteAll ?

Code: Alles auswählen

qDeleteAll(labels); labels.clear();
Wie wäre es ganz ohne Liste:

Code: Alles auswählen

foreach (QLineEdit* le, findChildren<QLineEdit*>())
{ 
    if (le->close())
      le->deleteLater();
}
Wie wäre es damit zu checken ob die Anzahl neuer Attribs (>, <, ==) der Alten sind .. dann brauchste nur ein paar (löschen oder einfach mit hide() verstecken)/hinzufügen und kannst dann einfach überall die Beschriftungen neu setzen?
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
ghostboss
Beiträge: 28
Registriert: 25. September 2010 17:10

Beitrag von ghostboss »

Jo danke ich nehme mal die zweite Version ohne Liste^^
Wie wäre es damit zu checken ob die Anzahl neuer Attribs (>, <, ==) der Alten sind .. dann brauchste nur ein paar (löschen oder einfach mit hide() verstecken)/hinzufügen und kannst dann einfach überall die Beschriftungen neu setzen?
Ist das Löschen und neu erstellen so aufwändig?

Wie kann ich bei einem Layout (Grid oder Form) die Reihe löschen, oder das Layout reseten von mir aus?
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

Wenn du eine chirurgische OP mit deinem Prog steuerst ... vielleicht ... sonst eher nicht. Es ist eher einfe Frage des Geschmacks ... wenn du da nicht im 1/100 sekundentakt pollst (wenn du pollst geht da vermutlich was grundlegendes schief ...) und neu aufbaust solltes es dein System locker packen.

Mein "Gefühl" bei QLineEdits dabei:
Wenn ich wüsste das da maximal 20 Objekte kommen können, meist so 10-15 sind und seltenst weniger als 8 würde ich warscheinlich einmal 20 allokieren und gut - was nicht gebraucht wird wird versteckt.

Wenn da irgendwas von 5 bis 200 drin sein können würde ich warscheinlich 10 im Konstruktor reservieren, bei Bedarf welche nachlegen und wenn ich dann mal weniger brauch die verstecken die ich nicht brauche ... wenn das ganze nur alle 5 Minuten passiert oder so würde ich vielleicht immer alle löschen/neu erzeugen ... wenn das 20 mal in der Sekunde sicher nicht.

Wenn du Sachen in ein Layout packst und das dann dem Widget als Layout zuweist, übernimmt das Widget die Sachen des Layouts als child. Mit

Code: Alles auswählen

foreach (QLineEdit* le, findChildren<QLineEdit*>())
{
    if (le->close())
      le->deleteLater();
} 
werden die versteckt und gelöscht (evtl. verzögert) ... danach ist das Layout wieder blank.

Wenn du nen Rahmen brauchst ist QFrame dein Freund ... schau in die API ob das QLayoutIrgendwas davon erbt (spoiler: tuts nicht ...) ... aber du kannst einfach eine QGroupBox oder ein QFrame zwischen das Layout und das Widget packen ... die haben Rahmen ...

setAlignment in Zusammenhang mit Layouts ist mir noch nicht untergekommen, wurde gespeichert ;)
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
ghostboss
Beiträge: 28
Registriert: 25. September 2010 17:10

Beitrag von ghostboss »

Ich erstelle ein WYSIWYG HTML-Editor und beim click auf ein Html Element will ich alle Attribute des Elements in dem Widget anzeigen. Das sind von 1 - 20+ Elemente.

Und wie kommst du auf Rahmen? Oder war das nur so, weil ich ja nach Reihe gefragt habe :D.

Ich hab schon gesucht und gesucht aber ich finde nicht wie ich die Anzahl der Reihen im QFormLayout oder QGridLayout andern kann. Oder erstellt man das Layout immer lockal, ich hab das Layout global (Klassen-Member) erstellt.
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

Das mit dem QFrame bezog sich auf einen früheren Post von dir.

Du erstellst garkeine Reihen/Zeilen whatever. Du addest Widgets zum zum Layout, das Layout setzt du zB für ein QWidget ... wo das was liegt macht das Layout. Wenn du was zum QHBoxLayout packst, liegt das dann rechts(*) vom zuletzt geaddet'em Element. Wenn du was in ein QVBoxLayout packst erscheint das unten(*). Wenn du was in ein QGridLayout packst, erscheints da wo dus spezifizierst (row/col/rowspan/colspan). Wenn du im QFormLayout usw ....
Wenn du Mist spezifizierst passiert manchmal auch Mist, genauso wenn du Widgets anlegst und nicht ins Layout packst und nicht hide()st.

Wenn du wissen willst wieviele Reihen da drin sind ... blätter in der API
http://doc.trolltech.com/4.7/qlayout.html und "Kinder" : QBoxLayout, QFormLayout, QGridLayout, and QStackedLayout.

Je nach Sinn gibts da dann zB count() rowCount() columnCount() itemAt() getItemPosition() ... usw. Was im Layout dargestellt wird hängt von der Sichtbarkeit des Inhalts und des Parents ab:

Code: Alles auswählen

#include <QtGui>
#include <QtCore>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
//    TicTacToeWidget w;
//    w.show();

    srand(time(0));
    QWidget showIt;
    QHBoxLayout * hbl = new QHBoxLayout(&showIt);

    QFrame w;
    w.setFrameStyle(QFrame::Raised|QFrame::Box);
    QFrame w2;
    w2.setFrameStyle(QFrame::Raised|QFrame::Panel);

    hbl->addWidget(&w);
    hbl->addWidget(&w2);

    QVBoxLayout * vb1 = new QVBoxLayout (&w);
    vb1->addWidget(new QLabel("hier ist das SteuerFrame"));

    QVBoxLayout * vb2 = new QVBoxLayout (&w2);
    vb2->addWidget(new QLabel("hier ist das DisplayFrame"));
    vb2->setAlignment(Qt::AlignTop);


    QLabel * lab;
    QCheckBox * box;
    foreach (QString s1, QString("1.2.3.4.5").split("."))
    {
    foreach (QString s2, QString("a.b.c.d.e").split("."))
    {
        bool visible= (rand()%2 != 0);

        lab = new QLabel(s1+s2);
        lab->setVisible(visible);
        vb2->addWidget(lab);

        box = new QCheckBox(s1+s2);
        box->setChecked(visible);
        QObject::connect(box,SIGNAL(clicked(bool)),lab,SLOT(setVisible(bool)));

        vb1->addWidget(box);
    }
    }


    showIt.show();

    return a.exec();
}
(*) Disclaimer: Standardverhalten
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
ghostboss
Beiträge: 28
Registriert: 25. September 2010 17:10

Beitrag von ghostboss »

Code: Alles auswählen

class RowTest ...{

...

QFormLayout* layoutForm;

...

RowTest(){
    layoutForm = new QFormLayout;
}

void createAttribute(){
    ...
    layoutForm->addRow(...);
    ...
}

int getRows(){
    return layoutForm->rowCount();
}

};
So ungefähr sieht bei mir die Klasse aus. Die Methode "createAttribute" wird sehr oft aufgeruffen und da adde ich dem Layout Reihen zu. Auch wenn ich Labels und LineEdits lösche (in der createAttribute()) wächst die anzahl der Reichen.

Wie kann ich nun das vermeiden?
Oder erstellt man Layouts lockal (ich hab ja global)?
Nach 7 Klicks hab ich ca. 140 Reichen!
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

http://doc.trolltech.com/main-snapshot/ ... mbers.html

foreach (QLineEdit* le, findChildren<QLineEdit*>())
{
layout->removeWidget(le);
if (le->close())
le->deleteLater();
}


Es kann dir doch völlig egal sein wieviele rows das Layout hat ... wenn du das widget löscht ist die row halt leer ... na und?
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
ghostboss
Beiträge: 28
Registriert: 25. September 2010 17:10

Beitrag von ghostboss »

So, hab wieder ein Problem und zwar speichere ich in der Methode "createAttirbutes" das QWebElement in der Eigenschaft "webElement" und beim ausführen des Slots "setHtmlAttribute" greife ich auf das "webElement", aber es ist NULL obwohl der Slot nach der Methode ausgeführt wird. Wieso? Wenn ich direkt aus der "createAttributes" auf den Slot zugreife dann ist "webElement" nicht NULL??? Kapiere ich nicht.

Hier ist der Code:
HtmlAttributes.h

Code: Alles auswählen

#ifndef HTMLATTRIBUTES_H
#define HTMLATTRIBUTES_H

#include <QWidget>
#include <QWebElement>
#include <QLabel>
#include <QLineEdit>
#include <QComboBox>
#include <QFormLayout>

class HtmlAttributes : public QWidget{
    Q_OBJECT

private:
    QFormLayout *layoutForm;
    QList<QLabel*> labels;
    QList<QLineEdit*> lineEdits;
    QWebElement *webElement;

public:
    HtmlAttributes(QWidget* parent = 0);

    void createAttirbutes(QWebElement *web_element, QList<QString> html_attributes, QList<QString> html_commonAttributes);

public slots:
    void setHtmlAttribute(QString, QString);
};

#endif // HTMLATTRIBUTES_H
HtmlAttributes.cpp

Code: Alles auswählen

#include "HtmlAttributes.h"
#include "AttributeItem.h"

#include <QMessageBox>

HtmlAttributes::HtmlAttributes(QWidget *parent) : QWidget(parent){
    layoutForm = new QFormLayout;
}

void HtmlAttributes::createAttirbutes(QWebElement *web_element, QList<QString> html_attributes, QList<QString> html_commonAttributes){
//QMessageBox::information(this, "test", QVariant(findChildren<QLabel*>().size()).toString(), QMessageBox::Ok);

    // Alles löschen
    foreach(QLabel* label, findChildren<QLabel*>()){
        if(label->close())
            label->deleteLater();
    }

    foreach(QLineEdit* line_edit, findChildren<QLineEdit*>()){
        if(line_edit->close())
          line_edit->deleteLater();
    }
    // disconnect
    // ...

    if(layoutForm != NULL)
        delete layoutForm;
    layoutForm = new QFormLayout;

    webElement = web_element;


    // Tag Attribute erstellen
    AttributeItem* itemTag = new AttributeItem("tag", web_element->tagName().toLower());
    //connect(item, SIGNAL(setHtmlAttribute(QString,QString)), SLOT(setHtmlAttribute(QString,QString)));
    layoutForm->addRow(itemTag->getLabel(), itemTag->getLineEdit());

    // Allgemeine Attribute erstellen
    AttributeItem* itemCommon = new AttributeItem("Allgemein");
    layoutForm->addRow(itemCommon->getLabel());

    for(qint32 i=0; i < html_commonAttributes.size(); ++i){
        QString attributeName = html_commonAttributes.at(i);
        QString attributeValue = web_element->attribute(attributeName, "");

        AttributeItem* item = new AttributeItem(attributeName, attributeValue);
        connect(item, SIGNAL(setHtmlAttribute(QString,QString)), SLOT(setHtmlAttribute(QString,QString)));
        layoutForm->addRow(item->getLabel(), item->getLineEdit());
    }

    // Attribute erstellen
    AttributeItem* itemAttribute = new AttributeItem("Attribute");
    layoutForm->addRow(itemAttribute->getLabel());

    for(qint32 i=0; i < html_attributes.size(); ++i){
        QString attributeName = html_attributes.at(i);
        QString attributeValue = web_element->attribute(attributeName, "");

        AttributeItem* item = new AttributeItem(attributeName, attributeValue);
        connect(item, SIGNAL(setHtmlAttribute(QString,QString)), SLOT(setHtmlAttribute(QString,QString)));
        layoutForm->addRow(item->getLabel(), item->getLineEdit());

    }
    setLayout(layoutForm);

    //setHtmlAttribute("id", "bla");          // direkt Aufruf: webElement ist nicht Null !?
}

void HtmlAttributes::setHtmlAttribute(QString _attribute_name, QString _attribute_value){
    //QMessageBox::information(this, "test", _attribute_name +" "+ _attribute_value, QMessageBox::Ok);
    if(webElement->isNull())
        QMessageBox::information(this, "null", "", QMessageBox::Ok);
    else{
        QMessageBox::information(this, "test", "", QMessageBox::Ok);
        webElement->setAttribute(_attribute_name, _attribute_value);
    }


    //QMessageBox::information(this, "test", webElement->tagName(), QMessageBox::Ok);
}
AttributeItem.h

Code: Alles auswählen

#ifndef ATTRIBUTEITEM_H
#define ATTRIBUTEITEM_H

#include <QWidget>
#include <QLabel>
#include <QLineEdit>

class AttributeItem : public QWidget{
    Q_OBJECT

private:
    QLabel* label;
    QLineEdit* lineEdit;

public:
    AttributeItem(QString _label, QString _line_edit="", QWidget* parent=0);
    QLabel *getLabel();
    QLineEdit *getLineEdit();



public slots:
    void lineEdited();

signals:
    void setHtmlAttribute(QString, QString);
};

#endif // ATTRIBUTEITEM_H
AttributeItem.cpp

Code: Alles auswählen

#include "AttributeItem.h"

AttributeItem::AttributeItem(QString _label, QString _line_edit, QWidget* parent) : QWidget(parent){

    label = new QLabel(_label);
    lineEdit = new QLineEdit(_line_edit);

    connect(lineEdit, SIGNAL(returnPressed()), SLOT(lineEdited()));
}

QLabel *AttributeItem::getLabel(){
    return label;
}

QLineEdit *AttributeItem::getLineEdit(){
    return lineEdit;
}

void AttributeItem::lineEdited(){
    emit setHtmlAttribute(label->text(), lineEdit->text());
}

Und das bei QFormLayout die Anzahl der Reihen wächst finde ich irgendwie nicht gut. Nur bei 70 Klicks auf 20 Attribute-Element sind das 1400 Reihen und es wächst weiter (irgendwo wird doch Speicher belegt).
Deswegen lösche ich das Layout und erstelle es neu.
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

ich kenn mich mit dem QWebElement nicht aus ... aber das isNull() prüft nicht pob der Zeiger null ist sondern um das Element ein Nullelement (dh es wurde nur der defaultconstruktor benutzt, keine attribs geadded und so). Am besten teste gleich nach webElement = web_element; obs ein Nullelement ist ... wenn ja, dann macht das ja alles richtig, du steckst nur falsche Sachen rein ;)
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
ghostboss
Beiträge: 28
Registriert: 25. September 2010 17:10

Beitrag von ghostboss »

Nein nein nein :D das webElement kann nicht null sein, weil ich ja in der "createAttributes" Methode webElement was zuweise "webElement = web_element" und der Slot "setHtmlAttribute" wird danach aufgerufen.

Funktionsweise:
1. Klick auf ein Html Element löst "createAttributes" aus
2. "createAttributes" erstellt Labes und TextEdits und connectet TextEdits mit "setHtmlAttribute" (über "AttributeItem") und setzt webElement
3. beim Signal "returnPressed" (TextEdit press Enter) wird die "setHtmlAttribute" Methode ausgelöst
4. in "setHtmlAttribute" wird aufs webElement zugegriffen (welches in "createHtmlAttribute" bereits existiert)

Das webElement ist Null oder so?

Aber wenn:
1. ...
2. ...
2.1 "createHtmlAttribute" ruft "setHtmlAttribute" am ende auf
4. ...

Das webElement ist nicht Null und kann bearbeitet werden !!!

Wie existiert das webElement im ersten Fall nicht???
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

Ich glaube wir reden aneinander vorbei:

wenn du irgendwo das machst:

Code: Alles auswählen

HtmlAttribute attrib;

// mehr code 

QList<QString> htmlAttrList; 
htmlAttrList << "Aeins" << "Azwei" << "Adrei";

QList<QString> htmlCommAttrList; 
htmlCommAttrList << "Ceins" << "Czwei" << "Cdrei";

QWebElement * elem = new QWebElement;

// mehr code 

attrib.createAttirbutes(elem, htmlAttrList, htmlCommAttrList);
dann ist elem.isNull() trozdem TRUE das bezieht sich auf den INHALT des QWebElements nicht ob das ein Nullzeiger ist. Mögliche Fehlerquelle kann auch sein das QWebElements implicit shared sind ... wenn du das QWebFrame zwischendurch änderst wird das QWebElement ungültig ... nachzulesen in der doku.

Noch was anderes - deine AttributeItem Klasse erbt von QWidget ... aber du nutzt nirgends dessen Funktionalität ... es würde also QObject reichen.
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
ghostboss
Beiträge: 28
Registriert: 25. September 2010 17:10

Beitrag von ghostboss »

Jo bin erleichtert, habs geschafft :).

Das Problem war dass das QWebElement das ich der createAttributes übergeben habe eine lockale Variable war, wurde also lockal in einer anderen Klasse-Methode erstellt und deswegen war mein webElement leer und nicht NULL. Aber trozdem ist das doch komisch. Wenn ich nach dem Aufruff der createAttributes Methode die setHtmlAttribute Methode aufrufe, also direkt danach oder in createAttributes, dann konnte ich auf die lockale Variable zugreiffen!? Obwohl wenn ich mir den Code anschaue, in dieser Klassen-Methode wo die variable erstellt wird, wird auch ein Signal erstellt und solange Signal und Slot verbunden ist, ist auch die Methode offen und die lockale Variable existiert oder so :?: 8)
Antworten