Im Forum gab es ein Gespräch darüber, den Akkustand eines Laptops unter Linux mit der Qt-Bibliothek zu überprüfen. Tatsächlich stellt Qt derzeit keine Klasse zur Verfügung, mit der Sie den Ladezustand des Akkus überprüfen können, aber solche Funktionen können mithilfe von Bibliotheken von Drittanbietern wie libacpi. implementiert werden.
Versuchen wir, eine Anwendung zu erstellen, die zumindest einige Daten benötigt und wie folgt aussieht:
libacpi
Die Bibliothek selbst ist in C geschrieben und hat die folgenden interessanten Funktionen und Datenstrukturen:
- global_t - globale Datenstruktur, die die Anzahl der Lüfter, Batterien und Wärmezonen sowie die Struktur mit dem Netzteil speichert.
- init_acpi_batt(global_t *globals) - Batteriedateninitialisierung
- init_acpi_acadapt(global_t *globals) - Adapterdaten initialisieren
- init_acpi_fan(global_t *globals) - Lüfterdateninitialisierung
- init_acpi_thermal(global_t *globals) - Initialisierung von Daten zu thermischen Zonen
- read_acpi_batt(int num) - Batteriedaten lesen
- read_acpi_zone(int num, global_t *globals) - Daten der thermischen Zone lesen
- read_acpi_fan(int num) - Lüfterdaten lesen
- battery_t - Batteriedatenstruktur
- fans_t - Lüfterdatenstruktur
- thermal_t - Datenstruktur der thermischen Zone
- battery_t batteries [MAX_ITEMS] - ein Array von Batterien, Daten werden darin gespeichert, wenn read_acpi_batt aufgerufen wird
- thermal_t thermals [MAX_ITEMS] - Array von thermischen Zonen, Daten werden darin gespeichert, wenn read_acpi_zone aufgerufen wird
- fan_t fans [MAX_ITEMS] - Fans-Array, Daten werden darin gespeichert, wenn read_acpi_fan aufgerufen wird
Verwenden der Bibliothek
Um die Bibliothek in einem Qt-Projekt zu verwenden, müssen Sie:
- Installieren Sie die Bibliothek aus dem Repository:
sudo apt-get install libacpi-dev
- Verbinden Sie die Bibliothek in der Pro-Projektdatei:
LIBS += -lacpi
- Verbinden Sie die Header-Datei der Bibliothek mit der Quellcode-Datei, wo sie Daten über die Batterieladung erhält:
#ifdef __cplusplus extern "C" { #endif #include <libacpi.h> #ifdef __cplusplus } #endif
Hauptanwendungsfenster
Das Hauptanwendungsfenster ist eine Widget-Klasse, die mit einer ui-Datei erstellt wird und deren Schnittstelle von einem Grafikdesigner erstellt wird. Es hat eine ScrollArea, die ein Objekt der vertikalen Platzierung von Elementen enthält, Widgets, die dynamisch erstellt werden, je nachdem, was die Bibliothek finden konnte. Und es gibt auch eine Schaltfläche zum Starten des Lesens von Daten durch die Bibliothek.
Widget.h
Die Header-Datei deklariert Vektoren mit Widgets für Batterien, Lüfter und thermische Zonen. Außerdem wird ein Zeiger auf ein Widget mit Netzteil deklariert. Alle Widgets sind benutzerdefinierte Klassen. Etwas weiter unten wird der Code eines der Widgets als Beispiel angegeben.
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include "batterywidget.h" #include "adapterwidget.h" #include "fanwidget.h" #include "thermalwidget.h" namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private slots: void on_pushButton_clicked(); private: Ui::Widget *ui; QVector<BatteryWidget*> m_butteryWidgetList; // Вектор виджетов с батареями QVector<FanWidget*> m_fanWidgetList; // Вектор виджетов с вентиляторами QVector<ThermalWidget*> m_thermalWidgetList; // Вектор виджетов с тепловыми зонами AdapterWidget* m_adapterWidget; // Виджет для адаптера питания всегда один }; #endif // WIDGET_H
Widget.cpp
Da die Bibliothek in C geschrieben ist, hat sie einen prozeduralen Codeausführungsstil. Es gibt auch einen kleinen Trick. Tatsache ist, dass die Bibliothek mehrere globale Variablen hat, in die Daten geschrieben werden. Dies sind Arrays mit Lüftern, thermischen Zonen und Batterien.
Das heißt, wenn Sie die Funktion read_acpi_batt(1) aufrufen, schreiben Sie die Datenstruktur battery_t in die Zelle des Arrays batteries[1]. .
Um eine globale Struktur zu erstellen, die Daten über die Anzahl aller oben genannten Strukturen enthält, ist es jedoch erforderlich, Speicher zuzuweisen.
#include "widget.h" #include "ui_widget.h" #ifdef __cplusplus extern "C" { #endif #include <libacpi.h> #ifdef __cplusplus } #endif #include <QFileDialog> Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget), m_adapterWidget(nullptr) { ui->setupUi(this); } Widget::~Widget() { delete ui; } void Widget::on_pushButton_clicked() { // Выделяем память под глобальную структуру данных бибилотеки global_t *global = static_cast<global_t*>(malloc(sizeof(global_t))); // Инициализируем структуру для init_acpi_batt(global); // батареи init_acpi_acadapt(global); // адаптера питания init_acpi_fan(global); // вентиляторов init_acpi_thermal(global); // тепловых зон // Battery battery_t *binfo; // Если нашлись батареи, то считываем в цикле данные и добавляем виджеты for(int i=0; i < global->batt_count; i++) { read_acpi_batt(i); // считываем данные // которые считываются в специальный массив batteries - он есть в самой библиотеке binfo = &batteries[i]; BatteryWidget* butteryWidget; // Создаём виджет if (m_butteryWidgetList.count() <= i) { butteryWidget = new BatteryWidget(this); butteryWidget->setTitle(QString(binfo->name)); m_butteryWidgetList.append(butteryWidget); ui->verticalLayout->addWidget(butteryWidget); } else { // Или забираем его из списка виджетов butteryWidget = m_butteryWidgetList.at(i); } // Устанавливаем butteryWidget->setPercentage(binfo->percentage); // Процент заряда butteryWidget->setChargeTime(binfo->charge_time); // Время до полного заряда butteryWidget->setRemainingTime(binfo->remaining_time); // Время до полного разряда // Определяем статус заряда switch (binfo->charge_state) { case C_CHARGE: butteryWidget->setChargeState("Charging"); break; case C_DISCHARGE: butteryWidget->setChargeState("Discharging"); case C_CHARGED: butteryWidget->setChargeState("Charged"); case C_NOINFO: butteryWidget->setChargeState("No info"); default: butteryWidget->setChargeState("Error"); break; } } // Adapter // Настройка виджета для адптера питания adapter_t *ac = &global->adapt; if (!m_adapterWidget) { m_adapterWidget = new AdapterWidget(this); ui->verticalLayout->addWidget(m_adapterWidget); } // Здесь проверяем только, подключён или нет switch (ac->ac_state) { case P_AC: m_adapterWidget->setStatus("Runs on AC"); break; case P_BATT: m_adapterWidget->setStatus("Runs on battery"); default: m_adapterWidget->setStatus("Error"); break; } // Fan fan_t *finfo; // Если нашлись вентиляторы, то считываем в цикле данные и добавляем виджеты for(int i=0; i < global->fan_count; i++) { read_acpi_fan(i); // считываем данные // которые считываются в специальный массив fans - он есть в самой библиотеке finfo = &fans[i]; FanWidget* fanWidget; // Создаём виджет if (m_fanWidgetList.count() <= i) { fanWidget = new FanWidget(this); fanWidget->setTitle(QString(finfo->name)); m_fanWidgetList.append(fanWidget); ui->verticalLayout->addWidget(fanWidget); } else { // Или забираем его из списка виджетов fanWidget = m_fanWidgetList.at(i); } // Устанавливаем статус, включён или нет switch (finfo->fan_state) { case F_ON: fanWidget->setStatus("ON"); break; case F_OFF: fanWidget->setStatus("OFF"); default: fanWidget->setStatus("Error"); break; } } // Thermal thermal_t *tinfo; // Если нашлись тепловые зоны, то считываем в цикле данные и добавляем виджеты for(int i=0; i < global->fan_count; i++) { read_acpi_zone(i, global); // считываем данные // которые считываются в специальный массив thermals - он есть в самой библиотеке tinfo = &thermals[i]; ThermalWidget* thermalWidget; // Создаём виджет if (m_thermalWidgetList.count() <= i) { thermalWidget = new ThermalWidget(this); thermalWidget->setTitle(QString(tinfo->name)); m_thermalWidgetList.append(thermalWidget); ui->verticalLayout->addWidget(thermalWidget); } else { // Или забираем его из списка виджетов thermalWidget = m_thermalWidgetList.at(i); } thermalWidget->setTemperature(tinfo->temperature); // Устанавливаем температуру thermalWidget->setFrequency(tinfo->frequency); // и частоту } free(global); }
Widgets
Das Programm enthält Widgets für alle oben genannten Strukturen. Sie dienen lediglich dazu, Informationen anzuzeigen und dynamisch hinzuzufügen. Ich werde als Beispiel ein Widget geben, das Informationen über die Batterie anzeigt.
Batterie-Widget.h
#ifndef BATTERYWIDGET_H #define BATTERYWIDGET_H #include <QWidget> namespace Ui { class BatteryWidget; } class BatteryWidget : public QWidget { Q_OBJECT public: explicit BatteryWidget(QWidget *parent = 0); ~BatteryWidget(); void setTitle(QString title); // Название батареи (как определено в ОС Linux) void setPercentage(int percentage); // Процент заряда void setChargeTime(int chargeTime); // Время до полного заряда в минутах void setRemainingTime(int remainingTime); // Время до полного разряда в минутах void setChargeState(QString chargeState); // Состояние private: Ui::BatteryWidget *ui; }; #endif // BATTERYWIDGET_H
Batteriewidget.cpp
#include "batterywidget.h" #include "ui_batterywidget.h" BatteryWidget::BatteryWidget(QWidget *parent) : QWidget(parent), ui(new Ui::BatteryWidget) { ui->setupUi(this); } BatteryWidget::~BatteryWidget() { delete ui; } void BatteryWidget::setTitle(QString title) { ui->label_title->setText(title); } void BatteryWidget::setPercentage(int percentage) { ui->label_percentage->setText(QString::number(percentage)); } void BatteryWidget::setChargeTime(int chargeTime) { ui->label_charge_time->setText(QString("%1:%2").arg(chargeTime / 60).arg(chargeTime % 60)); } void BatteryWidget::setRemainingTime(int remainingTime) { ui->label_remaining_time->setText(QString("%1:%2").arg(remainingTime / 60).arg(remainingTime % 60)); } void BatteryWidget::setChargeState(QString chargeState) { ui->label_charge_state->setText(chargeState); }
Das Ergebnis der Bibliothek
Ich würde das Ergebnis der Arbeit der Bibliothek als zufriedenstellend bezeichnen, obwohl es den Prozentsatz der Batterieladung sowie die Zeit zum vollständigen Aufladen der Batterie bestimmt. Aber sie hat die Zeit vor der Entlassung nicht bestimmt. Und auch keine Lüfter und Wärmezonen gefunden. Ich glaube, dass auf meinem Laptop-Modell diese Daten einfach nicht verfügbar sind. Es gab auch periodische Abstürze der Anwendung beim Versuch, auf einige Strukturparameter zuzugreifen.
Der Screenshot am Anfang des Artikels zeigt die Daten, die die Bibliothek in meinem Laptop finden konnte. Natürlich sind dort nicht alle Daten angegeben, wenn Sie sich die Header-Datei der Bibliothek ansehen, werden Sie feststellen, dass die Strukturen eine reichhaltigere Auswahl an Parametern bieten. Aber ich denke, das reicht aus, um den Start der Bibliothek zu demonstrieren.
Versuchen Sie, das Projekt selbst auszuführen, und melden Sie sich nach Möglichkeit ab, wenn diese Bibliothek thermische Zonen und Lüfter in Ihrem Laptop findet.