Poprawny sposób reakcji na zmianę listy pendrive'ów – aktualizacja interfejsu

0

Witam, piszę program w Qt, który ma wypalać pliki iso na pendrivie(taki sam jak UltraISO). Chcę, aby w comboboxie aktualizacja dostępnych pendrivów następowała wtedy, gdy program dostanie komunikat od systemu o pojawieniu się/usunięciu jakiegoś urządzenia. Dowiedziałem się, że muszę do tego wykorzystać funkcję nativeEvent, która wywoła się automatycznie, gdy pojawi się pojawi się/zniknie jakiś pendrive. I teraz mam pytanie w jaki sposób mam ją wykorzystać? Czy mam stworzyć nową klasę, która dziedziczy po QFrame i tam umieścić tę funkcję?( w ten sposób właśnie zrobiłem i nie działa) Czy mam moją główną klasę programu dziedziczyć po QFrame i tam ją umieścić? Z tego co czytałem to klasa główna nie powinna być modyfikowana. A może brakuje czegoś w mojej funkcji? Aktualnie powinien zostać nadpisany mój Textedit, gdy jakieś urządzenie się pojawi lub zniknie. ISO to główna klasa programu.

class Native
	: public QFrame, public ISO
{
	Q_OBJECT

		bool nativeEvent(const QByteArray &, void * message, long * result) override
	{
		auto & msg = *static_cast < const MSG *>(message);
		if (msg.message == WM_DEVICECHANGE)
		{			
			ui.textEdit_wiadomosc->append("Zmiana");		
		}

		return false;
	}
};

------------------------------------------------------

ISO::ISO(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);
	QTimer *checkingForAvailablePendrives = new QTimer(this);
	connect(checkingForAvailablePendrives, SIGNAL(timeout()), this, SLOT(checkingForAvailablePendrives()));
	connect(ui.pushButton_zapisz, SIGNAL(clicked()), this, SLOT(showAvailablePendrives()));
	checkingForAvailablePendrives->start(1000);
	connect(ui.pushButton_zamknij, SIGNAL(clicked()), this, SLOT(closeProgram()));
}

--------------------------------------------------------

class ISO : public QMainWindow
{
	Q_OBJECT

public:
	ISO(QWidget *parent = 0);
	~ISO();

protected:
	Ui::ISOClass ui;
	
private slots:
	void showAvailablePendrives();
	void checkingForAvailablePendrives();
	void closeProgram();
};
0

Utwórz nową klasę odpowiedzialną z obsługę tego komunikatu i wysyłaj z niej sygnał.

0

No to w ten sposób zrobiłem, utworzyłem klasę Native, ale nie brakuje jeszcze czegoś czy zrobiłem coś źle?

0

Ale dlaczego Native jest ramką?

0

Nie rozumiem?

0

Native dziedziczy po QFrame. Po co?

0

Widziałem przykładowy kod, który dziedziczył i zrozumiałem, że jest to wymagane. To w takim razie jak to powinienem zrobić?

0

Utwórz klasę, która obsługuje ten message. Nie jestem pewien jak to zrobić - to powinno być opisane w linku, który znalazłeś.

class PendriveWatcher
// możliwe, że musi dziedziczyć po jakimś interfejsie, możliwe, że nie
                : public QNativeWindows
{
    Q_OBJECT;
public:
    PendriveWatcher(QObject*);

    bool nativeEvent(const QByteArray &, void * message, long * result) override
    {
        auto & msg = *static_cast < const MSG *>(message);
        if (msg.message == WM_DEVICECHANGE)
        {           
            emit stateChanged();    
        }
 
        return false;
    }

signals:
    void stateChanged();
};

Potem łączysz ten sygnał z odpowiednim slotem.

0

A czy to robi różnicę, jeśli w ifie emituję sygnał zamiast bezpośrednio nadpisuje np textedit? Czy i w jednym i w drugim przypadku powinno to zadziałać?

0

Zależy co robisz z tym Native, nie przedstawileś nigdzie przykładu użycia.

0

Bo nie wiem do końca w jaki sposób go użyć, przedstawiłem cel jaki chcę osiągnąć. Chciałbym odświeżać listę pendrivów, gdy nadejdzie komunikat od systemu o pojawieniu się/usunięciu jakiegoś urządzenia i do tej pory dowiedziałem się, że służy do tego funkcja nativeEvent(). I nie potrafię tego zrobić. Ta funkcja podobno wywołuje się automatycznie, ale nie potrafię jej użyć.

2

Tworzysz klasę dziedziczącą po QAbstractNativeEventFilter i implementujesz metodę nativeEventFilter. (w zasadzie identycznie jak zrobił to @kq)
Później gdzieś w kodzie inicjalizującym dodajesz:

QAbstractEventDispatcher::instance()->installNativeEventFilter( instancja_twojej_klasy );
0

Udało mi się rozwiązać problem i rozwiązanie było bardzo blisko...Myślałem, że te dziedziczenie po QFrame jest konieczne, a jak napisał kq, że nie jest to później zorientowałem się, że mogę w takim razie tę funkcję umieścić w klasie głównej i wtedy zadziałało. Głupi błąd z mojej strony. Dziękuję Wam za pomoc :)

1

Zasady, które naruszyłeś, a obowiązują w Qt

  • QObject może być odziedziczony tylko raz (ty dziedziczysz po QFrame i po ISO które dziedziczy po QMainWindow).
  • jeśli kasa dziedziczy QObject lub jego potomka to musi być wymieniona na pierwszej pozycji
  • jeśli kasa dziedziczy QObject lub jego potomka to musi zawierać macro Q_OBJECT
0

Trochę nie rozumiem, bo ja po QObject chyba nie dziedziczę? I makro Q_OBJECT mam w obydwu klasach to to jest błąd?

1

QFrame to QObject.

Choć nie do końca kupuję używanie Q_OBJECT koniecznie, jeśli tylko overridujesz jakąś funkcję wirtualną.

1

Makro Q_OBJECT jest potrzebne, bo w przeciwnym razie klasa nie będzie miała meta danych i w związku z tym parę rzeczy nie będzie działać:

  • qobject_cast<dana_klasa>(cos);
  • sygnały i sloty
  • property

Funkcje wirtualne mają z tym niewiele wspólnego.

0

W tym przypadku mają wiele, bo overridujesz funkcję wirtualną nativeEvent, a wszystko inne o czym wspominasz nie jest używane.

0

Nie rozumiem trochę, że QFrame to QObject? QObject to jest jakby klasa bazowa wszystkich klas? Tak to działa czy źle to rozumiem?
I w takim razie jeśli w klasie ISO mam Q_OBJECT i w klasie Native mam Q_OBJECT, a ta dziedziczy po ISO to dubluje ten Q_OBJECT a to jest błąd tak?

1

QFrame to QObject: http://doc.qt.io/archives/qt-4.8/qframe.html
QObject to klasa bazowa dla wszystkich obiektów Qt: http://doc.qt.io/archives/qt-4.8/qobject.html

2

https://doc.qt.io/Qt-5/qfilesystemwatcher.html

Swoją drogą nie wiem czy QWidget::nativeEvent, w ogóle będzie wywołane dla eventów związanych z pendrive.
W końcu ta klasa jest związana z UI, a nie ze wszystkimi możliwymi zdarzeniami systemowymi.
Z tego powodu polecam sprawdzić jak działa QFileSystemWatcher.

Inna możliwość to poszukałbym jak używać QAbstractNativeEventFilter i to chyba bardziej pasuje do twoich wymagań.

Disclaimer: nigdy tego nie używałem, po prostu przeszukuje dokumentację. Radzę nabyć taką umiejętność.


LAST EDIT: O znalazłem dokładnie to co potrzebujesz: https://www.codesd.com/item/detected-a-new-usb-device-connected-disconnected-on-qt.html i jest to zrealizowane za pomocą `QAbstractNativeEventFilter` i widać jak należy tego używać. Biorąc pod uwagę niedoróbki tego artykułu to nie traktowałbym go jako pewne źródło wiedzy. IMO jest jednak na tyle informacji by zrobić to jak należy.
0

Dzięki wielkie za pomoc i informacje. Ogólnie już sobie poradziłem z tym problemem, napisałem wyżej gdzie robiłem błąd. Przez dziedziczenie po QFrame nie mogłem tego umieścić w klasie głównej, a gdy już umieściłem po usunięciu QFrame działa to tak jak chciałem, aktualizuje mi comboBoxa z dostępnymi literkami pendrivów, ale i tak mam tu jeszcze parę rzeczy do dodania to trochę zabawy przede mną. Marek co do przeszukiwania dokumentacji to masz rację, dużo szukam w niej i często dużo też z niej wyciągam, ale wydaję mi się, że to jest też kwestia doświadczenia. Bo zdarza się też, że patrzę do dokumentacji, ale po prostu nie wiele mi to pomaga i muszę jakiś rzeczywisty przykład zobaczyć. Myślę, że z czasem będzie to coraz lepiej szło.

1 użytkowników online, w tym zalogowanych: 0, gości: 1