Zugriff von außen auf GUI

Alles rund um die Programmierung mit Qt
Antworten
lara
Beiträge: 5
Registriert: 25. Juli 2010 22:01

Zugriff von außen auf GUI

Beitrag von lara »

Hallo Qt-Programmierer,

ich arbeite an einem Projekt, indem ich ein Hardware-Modul simulieren werden muss.
Das Hardware selber ist eine Aufzugsimulation.

Die Gui habe habe ich schon geschafft.

Was ich jetzt allerdings noch nicht hingekriegt habe,dass ich von außen auf meiner Gui nicht zugreifen kann (und zwar durch kleine Applikation).

für die Simulation steht ein Treiber zur Verfügung:
Der Treiber bekommt die folgenden beiden, neuen Zugriffsfunktionen
(Interfaces):

fd = open( "/dev/wasco.simu", O_RDWR );

read( fd, &lamps, sizeof(status) );
write( fd, &keys, sizeof(control) );

Die Simulation schickt folgende Kommandos an den Treiber
(Änderung eines Bits) per write:
- Taste xy gedrückt.
- Taste xy losgelassen.
Das Statuswort wird im Treiber so lange "vorgehalten", bis ein neues
Statuswort geschickt wird.
Der Treiber schickt an die Simulation die folgenden Informationen:
- 32-Bit-Statuswort, welches (letztlich) den Status der LEDs wiederspiegelt.

ich hab schon anhand einen zweiten Thread, eine Lösung zu finden hat das aber nicht geklappt. !!!!!!!!

Hat jemand eine Idee wie man das lösen könnte? wäre ich sehr dankbar !!!!
Dateianhänge
lift_simulation.tar.gz
(40.17 KiB) 122-mal heruntergeladen
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Ich habs nun mehrmals gelesen, aber ich verstehe weder die Ausgangslage (simuliert der "Treiber" die Hardware oder hängt da ein echtes Stück Hardware dran, welches wiederum die grösseren (Lift-)Komponenten simuliert?) noch das Problem..

Was genau funktioniert denn nicht?
lara
Beiträge: 5
Registriert: 25. Juli 2010 22:01

Beitrag von lara »

also die Aufgabe ist ganz einfach , im Labor gibt s ein Hardware-Modul für eine Aufzug- Simulation, welche ich mit Qt visualisieren soll.


Der Treiber ist fürs Hardware und sollte auch für meine Gui passen.

schreibt man eine kleine Applikation:

Code: Alles auswählen

#include <stdio.h>
#include <fcntl.h>

int main( int argc, char **argv )
{
	unsigned int fd_simu, lamps ,key;
	fd_simu = open("/dev/wasco.simu", O_RDWR );
	if( fd_simu < 0 )
		return -1;

	lamps=0x000000ff;
	write( fd_simu, &lamps, sizeof(value) );

while(1){
read( fd_simu, &key, sizeof(key) );
sleep(1);
value+=1;
}
	return 0;
}


als Ergebnis erwartet man eine Darstellung dieses Wert(amps=0x000000ff) auf GUI.
d.h die entsprechende LED's müssen leuchten.

der Treiber funktioniert ganz richtig!einfach laden mit :
  • insmod wascoloesung.ko
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Soweit so gut, aber worin besteht genau das Problem?
Im periodischen Auslesen? Falls ja, dann suchst du evt. das da:
http://doc.trolltech.com/4.6/qobject.html#startTimer
lara
Beiträge: 5
Registriert: 25. Juli 2010 22:01

Beitrag von lara »

wie kann ich die Werte (von Ausgaberegister) auf GUI darstellen lassen
wenn lamps =0x00001 muss die 1.LED usw.................. :

Code: Alles auswählen

while(1){
read(fd_simu,&lamps,sizeof(lamps));

if(lamps&0x0001){led[0].on();}
if(lamps&0x0002){led[1].on();}
if(lamps&0x0004){led[2].on();}
if(lamps&0x0008){led[3].on();}
if(lamps&0x0010){led[4].on();}
if(lamps&0x0020){led[5].on();}
if(lamps&0x0040){led[6].on();}
if(lamps&0x0080){led[7].on();}
if(lamps&0x0100){led[8].on();}
if(lamps&0x0200){led[9].on();}
if(lamps&0x0400){led[10].on();}
if(lamps&0x0800){led[11].on();}
if(lamps&0x1000){led[12].on();}
if(lamps&0x2000){led[13].on();}
if(lamps&0x4000){led[14].on();}
}
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

So langsam verstehe ich... mit "von aussen" meinst du in diesem "while"-loop....?
Das funktioniert so nicht mehr.. diese periodische Abfrage machst du entweder in einem Slot von myGui (getriggert durch einen QTimer) oder durch die vorhin erwähnte timerEvent-Methode.
Darin kannst du dann wie bisher den Zustand abfragen und die GUI-Objekte (z.B. testweise mal eine QCheckBox) setzen.

Wenn der read-Aufruf immer was liefert (als nie blockierend ist) würde ich keine Threads nehmen.

hth..

[EDIT]
Die obigen if-Statements kannst du übrigens auch vereinfachen (besonders, wenn die LEDs auch wieder ausgeschaltet werden müssen).

so in etwa:

Code: Alles auswählen

for (int i=0; i<15; i++)
    led[i]->setOn((1 << i) & lamps);
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Vielleicht so:

Beitrag von padreigh »

siehe Anhang. Ich trickse ein wenig und nutze QToolButton's mit einem QIcon als Anzeige. Wenn der Button inaktiv ist, graut QIcon mir den aus ... das ist zwar nicht schön, aber ein Anfang ... vor allem die Umwandlung aus 32-bit-Zahl zu Anzeige kannst du dir anschauen, ich hoffe du verstehst meinen Code :)

Code: Alles auswählen

class Lights : public QWidget {
    Q_OBJECT
public:
    Lights(QWidget * parent = 0, Qt::WindowFlags f = 0) : QWidget(parent,f)
    {
        // init for random generation of numbers
        qsrand(QTime().msecsTo(QTime::currentTime()));

        QGridLayout * lay = new QGridLayout();

        QToolButton * b;

        for (int i=0;i<32;++i)
        {
            b = new QToolButton();
            b->setIcon(QIcon(":image/on"));
            b->setEnabled(false);
            b->setAutoRaise(true);

            buttons.push_back(b);
            lay->addWidget(b,1,i,1,1);
        }
        // nen Button der sogar was tut ... eine randomZahl setzen
        b = new QToolButton();
        b->setArrowType(Qt::RightArrow);
        connect (b,SIGNAL(clicked()),this,SLOT(randomConfig()));

        lay->addWidget(b,2,1,1,1);

        QLabel * l = new QLabel(getState());
        l->setObjectName("label");
        lay->addWidget(l,2,2,1,31);

        setLayout(lay);
    }

    ~Lights() { /* all in layouts so no cleanup needed */ }

public slots:
    /** setz ne zufällige kombination */
    void randomConfig()
    {
        QString asbits;

        for (int i=0;i<32;++i) {
            if (qrand() % 2 == 0)   { asbits.push_back('0'); }
            else                            { asbits.push_back('1'); }
        }
        setState(asbits);
    }


    /** setz nen 32 bit unsigned integer */
    void setState(const quint32 & s)
    {
        state = s;
        setState(QString::number(state,2));
    }


    /** aktueller state als string und quint32 */
    const QString getState(quint32 * asNumber = 0)
    {
        QString asbits;

        foreach(QToolButton * b, buttons) {
            if (b->isEnabled())    { asbits.push_back('1'); }
            else                         { asbits.push_back('0'); }
        }

        if (asNumber) {*asNumber= state;}

        return asbits;
    }

private slots:
    void setState(const QString & asbits)
    {
        int i=0; // index in den string
        foreach (QChar c, asbits) // betrachte string character-weise
        {
            QToolButton * b = buttons[i]; // krieg zugehörigen button raus
            if (c=='1')         { b->setEnabled(true); }
            else                 { b->setEnabled(false); }

            ++i; // den index hochzählen damit auch der button stimmt
        }

        QLabel * l = findChild<QLabel*>("label"); // nimm das label
        l->setText(asbits); // und pack den string da rein
    }

private:
    quint32 state; // enthält den derzeitigen state
    QVector<QToolButton*> buttons; // enthält 32 pointer auf buttons
};
:/image/on ist ein simples 64x64 png mit einem gelben Icon drin als QtRessource eingebunden ... siehe Anhang

edit::
- bisserl kommentiert(nur hier, nicht im getar'ten quelltext)
- überflüssiges raus
- attachment update
Dateianhänge
LightsOn.tar.gz
Die Funktionalität sitzt in 'class Lights{}' in der QMainWindow.h ... der Rest ist nur DemoDekor.
(4.4 KiB) 119-mal heruntergeladen
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
lara
Beiträge: 5
Registriert: 25. Juli 2010 22:01

Beitrag von lara »

@solarix
du hast mich irgendwie schon verstanden aber nicht so ganz!!!
mit " von außen" meinte ich z.B wenn man meine GUI mit eigenem Programm steuern will.
einfach per read() und write() auf meine exe-Datei zugreifen.

z.B

Code: Alles auswählen

   write( fd_simu, &lamps, sizeof(value) ); 
sollte den Wert von lamps in meinem Programm gewechselt werden & in der GUI widergespiegelt. d.h die entsprechende LEDs müssen indem Fall leuchten.......

deswegen hab ich an einem zweiten Thread gedacht .

ich habe zwischendurch auch mit der Signal/Slot- Verfahren probiert,(eigene Signal)

Code: Alles auswählen

QObject::connect(this,SIGNAL(valueChanged()),led[i],SLOT(on()));
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

lara hat geschrieben: mit " von außen" meinte ich z.B wenn man meine GUI mit eigenem Programm steuern will.
einfach per read() und write() auf meine exe-Datei zugreifen.
:? ich verstehe von mal zu mal weniger... Also:

- du hast ein "Liftsimulator" in Form eines Gerätes mit Tasten und Lampen usw.
- weiter hast du ein Treiber dafür geschrieben, welcher du mit einem einfachen C-Programm getestet hast (der Treiber funktioniert, oder?)
- nun möchtest du eine GUI, mit welcher du
1. den aktuellen Zustand (Lampen/Schalter) anzeigen und
2. später auch noch steuern (ein/aus) möchtest.
- Weil Qt keine einfache "LED" hat, hast du KLed von KDE eingesetzt.

Wenn ich dich richtig verstehe, weisst du nun zwar, wie du den Status auslesen kannst, aber nicht, wie du ihn anzeigen sollst.

Also:
Du kannst kein "while (1)" mehr nehmen, weil alle graphischen Frameworks einen Eventloop (Maus/Tastatur/graphische Updates/Timer/usw.) besitzen. Daher musst du nun einen Timer aufsetzen, über welchen du periodisch (z.B. mit 10Hz) den Status ausliest und dann die Instanzen der GUI steuerst. Dies kannst du mit einem eigenen QTimer machen, oder die Timer-Methoden der QObject-Klasse verwenden:

Code: Alles auswählen

myGui ::myGui ()
{
  ...
  startTimer(100); // 100ms -> 10Hz
}

void myGui::timerEvent(QTimerEvent *event)
{
  read(fd_simu,&lamps,sizeof(lamps)); 
  qDebug() << "myGui::timerEvent" << lamps; // Status auf Konsole ausgeben;
  
  for (int i=0; i<15; i++)
    led[i]->setState( (1 << i) & lamps ? KLed::On : KLed::Off);
}
Siehe auch
http://doc.trolltech.com/4.6/qobject.html#startTimer (Timer in QObject)
http://doc.trolltech.com/4.6/qtimer.html#details (QTimer)

Dann noch ein paar weitere Punkte: eine GUI sollte nicht einfach so "hingeknallt" werden sondern sollte genau so sorgfälltig gemacht werden wie der Rest des Projektes (Treiber und Hardware).
Also:

- überlege dir sinnvolle Strategien bei der Namengebung ("myGui" ist Mist)
- verwende soweit möglich Qt-Klassen (QFile)
- denke objektorientiert; evt. lohnt es sich, für das Hardware-Interface (read/write-Aufrufe) eine eigene Klasse zu schreiben ("LiftInterface" oder so)
- void myGui::setbit() ist viel zu gross, verwende QSignalMapper!
- verwende für den UI-Entwurf den Designer, das ist einfacher. Wie du dann die UI-Datei anwenden kannst, steht hier: http://doc.trolltech.com/4.6/designer-u ... -file.html
- Mit KLed bist von was grossem abhängig (KDE), obwohl das auch in Qt nicht so schwierig wäre. Es ist ok, wenn du dein Programm vorerst mit KLed in Betrieb nimmst, aber ich würde mich noch um einen Qt-Ersatz kümmern (eigenes QWidget, welches im paintEvent das LED malt).

hth..
lara
Beiträge: 5
Registriert: 25. Juli 2010 22:01

Beitrag von lara »

@solarix
Du bist aber soweit ! und hast nun alles was ich brauche schon im Griff,
jetzt sehe ich schon was in meiner GUI !!!!!!!Schritt nach vorne
ich hab deinen Code verwendet ?! und habe es ganz normal Kompiliert ,stürzt aber beim Ausführen wieder ab!!!!!und kommt diese fehlermeldung raus:
segmentation fault .
aber wenn ich statt

Code: Alles auswählen

for (int i=0; i<15; i++)
        led[i]->setState( (1 << i) & lamps ? KLed::On : KLed::Off);
eine einfache if-Anweisung nutze ---->reagiert beim Testen nur noch die 1. Lampe und bleibt unveränderlich die anderen nicht!!!!
myGui::timerEvent 1
myGui::timerEvent 1
myGui::timerEvent 1
myGui::timerEvent 1
myGui::timerEvent 1
myGui::timerEvent 1
myGui::timerEvent 1
d.h lamps bleibt immer bei dem Wert =1. Das ist gar nicht der Fall

What's Wrong?

scheint aber nicht mit Sachen klar zu kommen

Viele Grüße

Lara
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Problem 1: segmentation fault
Das ist ein Pointerproblem: du hast nicht alle led-Instanzen aufgesetzt (in mygui.cpp). Beispiel:

Code: Alles auswählen

  // in mygui.h 
  public :
        ...
        KLed *led[16];

  // in mygui.cpp Constructor
         led[0] = new KLed(this);
         ...
         led[15] = new KLed(this);

  // in mygui.cpp timerEvent:
       for (int i=0; i<=15; i++)
        led[i]->setState( (1 << i) & lamps ? KLed::On : KLed::Off);
Problem 2: da können wir dir nicht weiterhelfen.. wenn der Treiber was falsches liefert, musst du den Treiber genauer anschauen. Funktioniert das denn in einem simplen C-Programm (wie in deinem Beispiel.. du kannst da ja in deinem "main()" den Wert mit 'printf("%d\n",lamps)' ausgeben..)?
Antworten