[QT] Manipulowanie zmienną globalną


(eureka 170) #1

Witam, mój program wygląda następująco:

sym1.h

#ifndef SYM1_H

#define SYM1_H

#include 

#include 

#include 

#include 



class MyWindow: public QWidget

{

    Q_OBJECT;

public:

    MyWindow();

    ~MyWindow() {}

private:

    QLabel *label1;

    QLabel *label2;


protected slots:

     int Pierwszy();

 protected:

     QPushButton *pushButton_1;

     QPushButton *pushButton_2;

     MyWindow *adr;

};



#endif // SYM1_H

sym1.cpp

#include 

#include 

#include 

#include 

#include 

#include 

int z;

MyWindow::MyWindow (): QWidget()

{


    setGeometry (300,300,300,200);

    setWindowTitle ("Algorytm SJF");

   // int j = 75;

    pushButton_1 = new QPushButton(this);

    pushButton_1->setObjectName(QString::fromUtf8("pushButton_1"));

    pushButton_1->setGeometry(QRect(10, 10, 100, 27));

    pushButton_1->setText("Przycisk 1");

    connect(pushButton_1,SIGNAL (clicked()),this, SLOT(Pierwszy()));


   // int z = Pierwszy();

    QLabel * wsk[z];

    int j = 75;

    for(int i=0;i
    {

        wsk[i] = new QLabel (this);

        wsk[i]->setGeometry(j,80,175,20);

        wsk[i]->setText("+");

        j = j+10;

    }

    /*for(int b=0;b
    {

        delete wsk[b];


    }*/


    label2 = new QLabel(this);

    label2 ->setGeometry(70,90,175,20);


}

int MyWindow::Pierwszy()

{


    bool ok;

    z = QInputDialog::getInteger(this,"Pobieranie liczby","Podaj wartośc", 0,-100,100,1,&ok);

    label2->setNum(z);

    return z;

}

main.cpp

#include 

#include "sym1.h"


int main(int argc, char *argv[])

{

    QApplication app (argc, argv);

    QTextCodec::setCodecForCStrings (QTextCodec::codecForName ("Windows-1250"));

    MyWindow window;

    window.show ();

    return app.exec();

}

Chciałem, by po naciśnięciu przycisku "ok" program wyświetlił mi w głównym oknie "+".

Nie rozumiem, dlaczego mimo, że z jest zmienną globalną, to cały czas wynosi ona 0 i przez to nie rysuje mi plusów w głównym oknie?


(Sawyer47) #2

Nie powinno się używać zmiennych globalnych w 99,99% przypadków.

Pierwszy to metoda, masz z jej poziomu dostęp do this, możesz wywołać inne metody i raczej w na tym oprzyj modyfikacje obiektu.

Nie do końca rozumiem co chciałeś osiągnąć tym kodem, ale jest raczej do przepisania.


(eureka 170) #3

Chciałem, by to wyglądało tak: klikam na przycisk - wyświetla mi się okno, gdzie mogę wpisać liczbę. Wpisuję np. 5. Po naciśnięciu "ok", w głównym oknie wyświetla mi się 5 plusów. Tylko nie wiem, dlaczego tutaj zmienna globalna nie działa.


(Sawyer47) #4

To nie wystarczy, jeśli będziesz miał jakiś label i w nim wyświetlać "+++++" dla z = 5 (o ile o to Ci chodzi). Wystarczy QString(z, '+').

Oczywiście z nie musi (i nie powinno) być zmienną globalną, wystarczy lokalna dla metody Pierwszy


(eureka 170) #5

A mógłbyś poprawić tę funkcję by to działało? Bo ja już nie mam kompletnie pomysłu

Mój plik sym1.cpp wygląda teraz następująco:

#include 

#include 

#include 

#include 

#include 

#include 

MyWindow *adr;

MyWindow::MyWindow (): QWidget()

{


    setGeometry (300,300,300,200);

    setWindowTitle ("Algorytm SJF");

    pushButton_1 = new QPushButton(this);

    pushButton_1->setObjectName(QString::fromUtf8("pushButton_1"));

    pushButton_1->setGeometry(QRect(10, 10, 100, 27));

    pushButton_1->setText("Przycisk 1");

    connect(pushButton_1,SIGNAL (clicked()),this, SLOT(Pierwszy()));

    adr = this;

   // int z = Pierwszy();

    /*for(int b=0;b
    {

        delete wsk[b];


    }*/

    str = new QString;

    label2 = new QLabel(this);

    label2 ->setGeometry(120,90,175,20);


}

int MyWindow::Pierwszy()

{

    int z = 0;

    bool ok;

    z = QInputDialog::getInteger(this,"Pobieranie liczby","Podaj wartośc", 0,-100,100,1,&ok);

    if(ok)

    {

        str->fill('+',z);


    }

    label2->setNum(z);

    return z;

}

Tylko, że mi tych plusów nie wyświetla w głównym oknie, po naciśnięciu ok pojawia się jedynie liczba od label2. Cały czas nie wiem, jak uzyskać zmienną z funkcji Pierwszy by móc jej użyć w konsktruktorze.


(Sawyer47) #6

A po co Ci w konstruktorze wartość, która zostanie podana dopiero po wciśnięciu przycisku? Nie rozumiem zupełnie po co Ci tablica QLabel, którą konstruujesz a potem od razu usuwasz... bez sensu dla mnie. Ja proponuję zrobić oddzielną labelkę na te plusy i kiedy zostanie wywołana metoda Pierwszy w jej ciele wykonać po prostu m_label3->setText(...)


(eureka 170) #7

Moim celem jest napisać program, ktory zasymuluje algorytm SJF. Chciałem, by użytkownik wpisał długość procesu, program wyświetla wtedy '+' i potem stopniowo je usuwa. Właśnie po to tworzę te obiekty i usuwam. Jeszcze, jak rozbuduję program dodam możliwość wpisania ilości procesów i wtedy program będzie usuwał procesy z najmniejszą ilością plusów, jednak zanim to zrobię to muszę rozwiązać problem z plusami. Zatem proszę Cię, jeżeli wiesz, jak rozwiązać mój problem ze zmienną 'z', moim sposobem, to napisz mi tutaj, bo męczę się z tym już drugi dzień a nadal nic nie wymysliłem, a nie mam zbyt dużo czasu, żeby to napisać. Będę ogromnie za to wdzięczny


(Sawyer47) #8

To ja pytam: czy nie możesz użyć jednej labelki i w ustawiać jej wartość na string zawierający odpowiednią liczbę plusów?


(eureka 170) #9

Możesz mi rozwinąć myśl/napisać ten kod? Bo ja nie potrafię się domyślić o co Ci chodzi

#include 

#include 

#include 

#include 

#include 

MyWindow::MyWindow (): QWidget()

{

    int a;

    z = 0;

    setGeometry (300,300,300,200);

    setWindowTitle ("Algorytm SJF");

    pushButton_1 = new QPushButton(this);

    pushButton_1->setObjectName(QString::fromUtf8("pushButton_1"));

    pushButton_1->setGeometry(QRect(10, 10, 100, 27));

    pushButton_1->setText("Przycisk 1");

    a = connect(pushButton_1,SIGNAL (clicked()),this, SLOT(Pierwszy()));

    label1 = new QLabel(this);

    label1 ->setGeometry(120,80,175,20);

  // label2 = new QLabel(this);

  // label2 ->setGeometry(120,90,175,20);

  // label2 ->setNum(z);

}

void MyWindow::Pierwszy()

{

    bool ok;

    z = QInputDialog::getInteger(this,"Pobieranie liczby","Podaj wartośc", 0,-100,100,1,&ok);

    if(ok)

    {


        for(int i=z;i>0;i--)

        {

            Sleep(100);

            label1->setText("+");

        }

    }


}

Jeżeli o to Ci chodziło, to powiem Ci, że Twój sposób nie działa. Napisz mi proszę poprawny kod dla funckji Pierwszy, bo nie wiem o co chodzi


(Sawyer47) #10

Miałem na myśli coś takiego:

MyWindow::MyWindow (): QWidget()

{

    setGeometry (300,300,300,200);

    setWindowTitle ("Algorytm SJF");

    pushButton_1 = new QPushButton(this);

    pushButton_1->setObjectName(QString::fromUtf8("pushButton_1"));

    pushButton_1->setGeometry(QRect(10, 10, 100, 27));

    pushButton_1->setText("Przycisk 1");

    connect(pushButton_1,SIGNAL (clicked()),this, SLOT(Pierwszy()));


	label1 = new QLabel(this);

	label1->setGeometry(40, 40, 175, 20);


    label2 = new QLabel(this);

    label2->setGeometry(70,90,175,20);


}

int MyWindow::Pierwszy()

{


    bool ok;

    int z = QInputDialog::getInteger(this,"Pobieranie liczby","Podaj wartośc", 0,-100,100,1,&ok);


    label1->setText(QString(z, '+'));

    label2->setNum(z);

    return z;

}

Btw. nie lepiej używać Layoutów zamiast na sztywno setGeometry?


(eureka 170) #11

ok, dzięki. A jaki jest sposób wyświetlania tekstu z opóźnieniem (w tym przypadku usuwanie plusów, ale z opóźnieniem, by ktoś, kto to widział, mógł na własne oczy zobaczyć, że te plusy się redukują)? Użyłem funkcji Sleep, jednak mimo tego nie uzyskałem zamierzonego efektu

MyWindow::MyWindow (): QWidget()

{

    setGeometry (300,300,300,200);

    setWindowTitle ("Algorytm SJF");

    pushButton_1 = new QPushButton(this);

    pushButton_1->setObjectName(QString::fromUtf8("pushButton_1"));

    pushButton_1->setGeometry(QRect(10, 10, 100, 27));

    pushButton_1->setText("Przycisk 1");

    connect(pushButton_1,SIGNAL (clicked()),this, SLOT(Pierwszy()));


   label1 = new QLabel(this);

   label1->setGeometry(40, 40, 175, 20);


    label2 = new QLabel(this);

    label2->setGeometry(70,90,175,20);


}

void MyWindow::Pierwszy()

{


    bool ok;

    int z = QInputDialog::getInteger(this,"Pobieranie liczby","Podaj wartośc", 0,-100,100,1,&ok);


    label1->setText(QString(z, '+'));


    for(int i=z;i>=0;i--)

    {

        label1->setText(QString(i,'+'));

       Sleep(1000);

    }


}

(Sawyer47) #12

Nie pisałem dawno dawno w Qt, ale wydaje mi się, że wystarczy użyć timerEvent wraz z QObject::startTimer i QObject::killTimer.

// Do pliku nagłówkowego dodajesz

    int m_timerid;

   void timerEvent(QTimerEvent *event);


// do cpp


void MyWindow::timerEvent(QTimerEvent *event)

{

	QString tmp = label1->text();

	tmp.chop(1);

	label1->setText(tmp);

	if (tmp.isEmpty())

		killTimer(m_timerid);

}


// oraz


label1->setText(QString(z, '+'));

m_timerid = startTimer(500);

No i lepsze niż Sleep, bo przenośne.


(eureka 170) #13

OK, a jest w QT możliwość tworzenia napisów w pętli w stylu np.

"Proces nr 1"

"Proces nr 2"

"Proces nr 3" ?

Gdybym pisał w konsoli można by było użyć

for(int i=0;i<3;i++)

{

     cout << "Proces nr " << i << endl;

}

a da się to zrobić za pomocą setText?


(Sawyer47) #14

W takim razie najpierw zbuduj taki napis w pętli, a potem go wyświetl.


(eureka 170) #15

Problem wyżej na razie zostawię.

Skorzystałem z Twoich porad, rozbudowałem program i teraz można wczytać ilość procesów i długość dla każdego procesu ( każdy proces będzie miał jakąś ilość plusów). Chciałem, żeby najpierw program wyświetlił wpisane plusy przez użytkownika i po naciśnięciu "ok" dla ostatniego procesu, program usuwał powoli plusy zaczynając od góry. Tu jest kod:

MyWindow::MyWindow (): QWidget()

{

    setGeometry (300,600,300,200);

    setWindowTitle ("Algorytm SJF");

    pushButton_1 = new QPushButton(this);

    pushButton_1->setObjectName(QString::fromUtf8("pushButton_1"));

    pushButton_1->setGeometry(QRect(10, 200, 100, 27));

    pushButton_1->setText("Zamknięta pula zadań");

    for(int i=0;i<10;i++)

    {

        label1[i] = new QLabel(this);

        label1[i]->setGeometry(40, (i+1)*10,175,20);


    }

   //label1->setGeometry(40, 40, 175, 20);


    label2 = new QLabel(this);

    label2->setGeometry(70,90,175,20);

    connect(pushButton_1,SIGNAL (clicked()),this, SLOT(Nowe_Okno()));

}

void MyWindow::Nowe_Okno()

{

    bool ok;

    x = QInputDialog::getInteger(this,"Pobieranie liczby","Podaj ilość procesów (od 1-10)", 0,-100,100,1,&ok);

    int *tab = new int[x];


    for(int i=0;i
    {

        tab[i] = Pierwszy(i);

    }

    if(x!=10)

    {

        for(int i=x;i<10;i++)

        {

           label1[i]->setText("");

        }

    }


    m_timerid = startTimer(500);

    if(ok)

    {

        for(int i=0;i
        {


            for(int j=0;j
            {

                tmp = new QString;

                *tmp = label1[i]->text();

                tmp->chop(1);

                label1[i]->setText(*tmp);

                if (tmp->isEmpty())

                    killTimer(m_timerid);

            }

        }

    }

    delete tab;

}


int MyWindow::Pierwszy(int g)

{


    bool ok;

    z = QInputDialog::getInteger(this,"Pobieranie liczby","Podaj wartośc", 0,-100,100,1,&ok);

    label1[g]->setText(QString(z, '+'));

    return z;



}

Tylko, że program zamiast robić to stopniowo, usuwa wszystko od razu i nie widać jego działania. Problem leży w tej funkcji ( na pewno musiałem ją źle napisać, bądź umieściłem w złym miejscu)

if(ok)

    {

        for(int i=0;i
        {


            for(int j=0;j
            {

                tmp = new QString;

                *tmp = label1[i]->text();

                tmp->chop(1);

                label1[i]->setText(*tmp);

                if (tmp->isEmpty())

                    killTimer(m_timerid);

            }

        }

    }

Co tu jest nie tak?


(Sawyer47) #16

Modyfikacja tych labelek z plusami powinna odbywać się w metodzie timerEvent, która jest przez timer wywoływana co określony czas,


(eureka 170) #17

A ta funkcja jest wywoływana przez m_timerid = startTimer(500);?

Jeżeli tak, to jak napisać ten fragment kodu:

if(ok)

    {

        for(int i=0;i
        {


            for(int j=0;j
            {

                tmp = new QString;

                *tmp = label1[i]->text();

                tmp->chop(1);

                label1[i]->setText(*tmp);

                if (tmp->isEmpty())

                    killTimer(m_timerid);

            }

        }

    }

w metodzie timerEvent? Żeby to działało to musiałbym przekazać tam dodatkowo argument x i tab, a jak napiszę m_timerid = startTimer(500,x,tab), to mi błąd wywala, że tak się nie da


(Sawyer47) #18

startTimer ma postać http://doc.qt.nokia.com/4.7-snapshot/qo ... startTimer

Przecież masz klasę, a w niej masz pola (zmienne składowe) - tam możesz zapisać dane, które mają być 'współdzielone' przez metody.

...

Btw. od ilu dni uczysz się programować?

PS Wczytałem się w dokumentację i wychodzi na to, że m_timerid jest zbędne


(eureka 170) #19

w QT uczę się programować od paru dni i się jeszcze gubię

Wsadziłem manipulowanie labelami w metodzie timerEvent

void MyWindow::Nowe_Okno()

{

    bool ok;

    x = QInputDialog::getInteger(this,"Pobieranie liczby","Podaj ilość procesów (od 1-10)", 0,-100,100,1,&ok);

    tab = new int[x];


    for(int i=0;i
    {

        tab[i] = Pierwszy(i);

    }

    if(x!=10)

    {

        for(int i=x;i<10;i++)

        {


           label1[i]->setText("");

        }

    }

    for(int i=0;i
    {

         a = i;

         m_timerid = startTimer(500);

    }


  // delete tab;

}


int MyWindow::Pierwszy(int g)

{


    bool ok;

    z = QInputDialog::getInteger(this,"Pobieranie liczby","Podaj wartośc", 0,-100,100,1,&ok);

    label1[g]->setText(QString(z, '+'));

    return z;



}

void MyWindow::timerEvent(QTimerEvent *event)

{

    QString *tmp;

    tmp = new QString;

    for(int i = 0;i
    {

        *tmp = label1[a]->text();

        tmp->chop(1);

        label1[a]->setText(*tmp);

         if (tmp->isEmpty())

            killTimer(m_timerid);

    }

tyle, że program usuwa plusy tylko dla ostatniego labelu i to w dodatku szybko, a nie tak jak miało być - wolno


(Sawyer47) #20

timerEvent jest wywoływany co 500ms - jeśli chcesz aby usuwał jeden plus to niech timerEvent usuwa jeden plus, a nie w pętli wszystkie. Na razie usuwasz cały czas z label1[a].

Ponadto niepotrzebnie tmp robisz wskaźnikiem, skoro to zmienna tymczasowa dla metody, wystarczy zwyczajna zmienna automatyczna.