Společnost Amazon miliardáře Jeffa Bezose vypustila na oběžnou dráhu první várku družic svého projektu Kuiper, který má z vesmíru poskytovat vysokorychlostní internetové připojení po celém světě a snažit se konkurovat nyní dominantnímu Starlinku nejbohatšího muže planety Elona Muska.
Poslední aktualizací začal model GPT-4o uživatelům příliš podlézat. OpenAI jej tak vrátila k předchozí verzi.
Google Chrome 136 byl prohlášen za stabilní. Nejnovější stabilní verze 136.0.7103.59 přináší řadu novinek z hlediska uživatelů i vývojářů. Podrobný přehled v poznámkách k vydání. Opraveno bylo 8 bezpečnostních chyb. Vylepšeny byly také nástroje pro vývojáře.
Homebrew (Wikipedie), správce balíčků pro macOS a od verze 2.0.0 také pro Linux, byl vydán ve verzi 4.5.0. Na stránce Homebrew Formulae lze procházet seznamem balíčků. K dispozici jsou také různé statistiky.
Byl vydán Mozilla Firefox 138.0. Přehled novinek v poznámkách k vydání a poznámkách k vydání pro vývojáře. Řešeny jsou rovněž bezpečnostní chyby. Nový Firefox 138 je již k dispozici také na Flathubu a Snapcraftu.
Šestnáctý ročník ne-konference jOpenSpace se koná 3. – 5. října 2025 v Hotelu Antoň v Telči. Pro účast je potřeba vyplnit registrační formulář. Ne-konference neznamená, že se organizátorům nechce připravovat program, ale naopak dává prostor všem pozvaným, aby si program sami složili z toho nejzajímavějšího, čím se v poslední době zabývají nebo co je oslovilo. Obsah, který vytvářejí všichni účastníci, se skládá z desetiminutových
… více »Richard Stallman přednáší ve středu 7. května od 16:30 na Technické univerzitě v Liberci o vlivu technologií na svobodu. Přednáška je určená jak odborné tak laické veřejnosti.
Jean-Baptiste Mardelle se v příspěvku na blogu rozepsal o novinkám v nejnovější verzi 25.04.0 editoru videa Kdenlive (Wikipedie). Ke stažení také na Flathubu.
TmuxAI (GitHub) je AI asistent pro práci v terminálu. Vyžaduje účet na OpenRouter.
Spousta programů má ve svém hlavním okně nabídku (menubar), panely nástrojů (toolbary), stavový řádek (status bar) a podobně. Qt pro tyto účely obsahuje třídu QMainWindow, která vytvoření hlavního okna usnadňuje. Následuje jednoduchý demonstrační program – je to pouze widget, takže je třeba vytvořit ještě main.cpp
, viz předchozí díl.
mainwindow.h
: Zde bych zmínil tzv. dopřednou deklaraci (forward declaration), která může zkrátit dobu potřebnou k sestavení programu. Použité třídy, jejichž API v hlavičkovém souboru nepotřebujeme (třeba členské proměnné), takto dopředu deklarujeme a #include
dáme až do implementačního .cpp souboru. Kompilátor díky tomu nebude zbytečně víckrát parsovat hromadu hlavičkových souborů, jen aby se dozvěděl, že taková třída opravdu existuje (protože to je jediná informace, kterou v tomto bodě potřebuje). Přímo vývojáři Qt tvrdí, že to v některých případech může mít poměrně velký vliv na dobu kompilace.
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> // dopředná deklarace class QDir; class QMessageBox; class QListWidget; class QListWidgetItem; class MainWindow : public QMainWindow { Q_OBJECT public: // v konstruktoru nepředáváme rodiče, protože jde o hlavní okno MainWindow(); private: QDir* m_dir; QListWidget* m_list; QString m_dName; private slots: void openDir(QString = QString()); void itemDoubleClicked(QListWidgetItem*); }; #endif
mainwindow.cpp
: Všimněte si slotu itemDoubleClicked
, kterému je předán ukazatel na uživatelem dvojkliknutou položku seznamu QListWidgetItem.
#include "mainwindow.h" #include <QApplication> #include <QMenuBar> #include <QToolBar> #include <QAction> #include <QFileDialog> #include <QDir> #include <QFileInfo> #include <QMessageBox> #include <QListWidget> MainWindow::MainWindow() : m_dir(0) { // vytvoříme panel s nabídkou QMenuBar* menuBar = new QMenuBar(this); // jednotlivá menu QMenu* menuFile = new QMenu(tr("&File")); QMenu* menuHelp = new QMenu(tr("&Help")); // položky menu QAction* actionOpen = new QAction(tr("&Open"), this); QAction* actionQuit = new QAction(tr("&Quit"), this); QAction* actionAboutQt = new QAction(tr("About Qt"), this); // nastavení klávesové zkratky actionOpen->setShortcut(QKeySequence("Ctrl+O")); // propojení položek menu s funkcemi programu connect(actionOpen, SIGNAL(triggered()), this, SLOT(openDir())); connect(actionQuit, SIGNAL(triggered()), qApp, SLOT(quit())); connect(actionAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt())); // přidáme položky do patřičných nabídek... menuFile->addAction(actionOpen); menuFile->addAction(actionQuit); menuHelp->addAction(actionAboutQt); //... a jednotlivá menu do panelu menuBar->addMenu(menuFile); menuBar->addMenu(menuHelp); // řekneme widgetu, aby použil naše menu setMenuBar(menuBar); // vytvoříme grafický seznam položek m_list = new QListWidget(this); // a nastavíme jej jako hlavní widget hlavního okna setCentralWidget(m_list); // dvojklik na seznam spustí náš slot connect(m_list, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(itemDoubleClicked(QListWidgetItem*))); resize(600, 400); } void MainWindow::itemDoubleClicked(QListWidgetItem* item) { // tato třída poskytuje informace o souborech a adresářích QFileInfo fileInfo(m_dName + "/" + item->text()); if(fileInfo.isDir()) openDir(fileInfo.canonicalFilePath()); else { // dialogy dovedou pracovat s jednoduchým HTML QString infotext = "<b>Name</b>: " + fileInfo.fileName() + "<br/><b>Location</b>: " + fileInfo.canonicalPath() + "<br/><b>Owner</b>: " + fileInfo.owner() + "<br/><b>Group</b>: " + fileInfo.group(); QMessageBox::information(this, tr("File info"), infotext); } } void MainWindow::openDir(QString dName) { if(!dName.isEmpty()) m_dName = dName; else do // dialog pro výběr existujícího adresáře m_dName = QFileDialog::getExistingDirectory(this, tr("Choose a directory")); while(m_dName.isEmpty()); m_dir = new QDir(m_dName); // Zde by bylo vhodné kontrolovat přístupová práva, // a patřičně na ně reagovat. Takto program nedostatečné // oprávnění ignoruje a seznam se vyprázdní. // vyprázdníme seznam m_list->clear(); // přidáme položky z adresáře do seznamu m_list->addItems(m_dir->entryList(QDir::AllEntries, QDir::Name)); delete m_dir; }
Velmi často se hodí možnost ukládat (a poté zpětně načítat) nastavení programu, a proto si ukážeme, jak to je jednoduché s třídou QSettings. Konfigurace se ukládá do souboru ~/.config/organizace/název_programu.conf
. Pokud budete chtít ukládat veškerou konfiguraci programu do jednoho souboru (což je běžné), pak je vhodné nastavit si název organizace a programu již do instance QApplication ve funkci main()
, abyste tyto údaje nemuseli zadávat pokaždé do konstruktoru QSettings
:
qApp->setOrganizationName("Organizace"); qApp->setApplicationName("SuperProgram"); // konfigurace bude v ~/.config/Organizace/SuperProgram.conf
Asi nejdůležitější 2 metody třídy QSettings
jsou:
void setValue(const QString& key, const QVariant& value)
- nastaví položce key
hodnotu value
.QVariant value(const QString& key, const QVariant& defaultValue = QVariant())
- vrátí hodnotu položky key
. Pro případ, že tato položka není v nastavení, můžete nastavit volitelnou výchozí hodnotu.Co je to QVariant? Jde o jakýsi kontejner, který dovede pojmout libovolný datový typ. Chová se jako union
pro základní datové typy C++ a Qt. Když chcete z proměnné tohoto typu dostat hodnotu, musíte vědět, jakého je hodnota typu (k tomu může v nejhorším pomoci metoda typeName()
, která vrátí název typu jako C řetězec) a zavolat patřičnou metodu toType()
, kde Type nahradíte za patřičný datový typ:
QVariant test(true); bool b = test.toBool(); QVariant numero(123); int n = numero.toInt();
A zde konečně přichází ukázkový program. Zkuste si napsat něco do textového pole a potom na spinboxu vybrat nějaké číslo. Nastavení uložte tlačítkem Save
, program ukončete a tlačítko Load
by vaše nastavení mělo načíst.
settings.h
:
#ifndef SETTINGS_H #define SETTINGS_H #include <QWidget> #include <QSettings> class QLineEdit; class QSpinBox; class Settings : public QWidget { Q_OBJECT public: Settings(); private: QSettings m_settings; QLineEdit* m_lineEdit; QSpinBox* m_spinBox; public slots: void loadSettings(); void saveSettings(); }; #endif // SETTINGS_H
settings.cpp
:
#include "settings.h" #include <QVBoxLayout> #include <QHBoxLayout> #include <QLineEdit> #include <QSpinBox> #include <QPushButton> Settings::Settings() { m_lineEdit = new QLineEdit(); m_spinBox = new QSpinBox(); //tlačítka pro načtení a uložení nastavení QPushButton* load = new QPushButton(tr("Load")); QPushButton* save = new QPushButton(tr("Save")); connect(load, SIGNAL(clicked()), this, SLOT(loadSettings())); connect(save, SIGNAL(clicked()), this, SLOT(saveSettings())); QHBoxLayout* wLayout = new QHBoxLayout(); wLayout->addWidget(m_lineEdit, 1); wLayout->addWidget(m_spinBox); QHBoxLayout* btnLayout = new QHBoxLayout(); btnLayout->addWidget(load); btnLayout->addWidget(save); QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(wLayout); layout->addLayout(btnLayout); setLayout(layout); } // načte nastavení - hodnoty načtené z konfiguračního souboru přiřadí patřičným objektům void Settings::loadSettings() { m_lineEdit->setText( m_settings.value("lineEdit", QString()).toString() ); m_spinBox->setValue( m_settings.value("spinBox", 0).toInt() ); } // uloží nastavení void Settings::saveSettings() { m_settings.setValue("lineEdit", m_lineEdit->text()); m_settings.setValue("spinBox", m_spinBox->value()); }
Na události jsme už jednou narazili v minulém díle, když jsme reimplementovali událost dvojkliku na speciální tlačítko. Tentokrát si ovšem kromě událostí myši zkusíme napsat i paintEvent()
, což je funkce, která má za úkol vykreslit a následně překreslovat widget. Překreslit můžeme také pouze danou oblast, takže toho pro efektivitu využijeme a ukážeme si, jak napsat velice jednoduché Malování :-)
painting.h
:
#ifndef PAINTING_H #define PAINTING_H #include <QWidget> #include <QPainter> class Painting : public QWidget { public: Painting(QWidget *parent = 0); protected: // hýbání myší virtual void mouseMoveEvent(QMouseEvent*); // stlačení tlačítka myši virtual void mousePressEvent(QMouseEvent*); // puštění tlačítka myši virtual void mouseReleaseEvent(QMouseEvent*); // událost kreslení virtual void paintEvent(QPaintEvent* e); private: bool m_painting; }; #endif // PAINTING_H
painting.cpp
:
#include "painting.h" #include <QMouseEvent> Painting::Painting(QWidget *parent) : QWidget(parent), m_painting(false) { // bílé pozadí setPalette(QPalette(QColor(255, 255, 255))); setAutoFillBackground(true); } // povolí kreslení void Painting::mousePressEvent(QMouseEvent* e) { m_painting = true; e->ignore(); } // zakáže kreslení void Painting::mouseReleaseEvent(QMouseEvent* e) { m_painting = false; e->ignore(); } // pokud je povolené kreslení, aktualizuje pixel pod kurzorem void Painting::mouseMoveEvent(QMouseEvent* e) { if(!m_painting) return; update(e->x(), e->y(), 1, 1); } // vykreslíme pixel, který máme aktualizovat void Painting::paintEvent(QPaintEvent* e) { QPainter p(this); // nastaví barvu "pera" p.setPen(Qt::black); // vykreslí tečku na daném bodě p.drawPoint(e->rect().x(), e->rect().y()); }
QPainter
toho dokáže mnohem víc, než jen kreslit tečky, ale podrobněji to v tomto seriálu nebudeme rozebírat, takže zájemce odkazuji na dokumentaci.
V příštím díle si mj. ukážeme, jak navrhnout GUI pomocí Qt Designeru a jak s takovým návrhem potom dále pracovat.
Nástroje: Tisk bez diskuse
Tiskni
Sdílej:
Musím souhlasit, že seriál není cílen pro úplné začátečníky a cílová skupina tak bude chudší než asi bylo zamýšleno. Ovšem pokud si je čtenář jistý svými C++ znalostmi, měl by se poměrně rychle problematikou prokousat.
Jediné, co by bylo pro úplné začátečníky přínosnější, by byla lokalizace celé Qt dokumentace do češtiny. K tomu ale není důvod, protože pokud není člověk schopný zvládnout (alespoň pasivně) technický anglický text tak, aby pochopil myšlenku (není potřeba překládat každé slovo a chápat gramatiku), nikdy z něj nebude programátor. Alespoň ne takový, který svede více než jen nahradu "Hello world!" za "Ahoj svete" (I když taky jsem měl radost jak decko, když se mi před mnoha lety podařilo poprvé přeložil změny v jednom demu podobného rozsahu )
Musím souhlasit, že seriál není cílen pro úplné začátečníky a cílová skupina tak bude chudší než asi bylo zamýšleno.Nesouhlas
Ovšem pokud si je čtenář jistý svými C++ znalostmi, měl by se poměrně rychle problematikou prokousat.Jak je řečeno jinde, článek je pro začátečníky v Qt, ne v C++
Já tenhle seriál vítám, alespoň se konečně dozvím, proč to je právě takhle
Jsem programátor v C, shell, PL/SQL. C++ jsem se ještě stále nenaučil, mám jen jakési povědomí o objektech a jak to zhruba funguje, ale to mi nezabránilo spáchat jeden plugin do kate (Konečně jsem jej začal přepisovat pro KDE 4) a podílet se na vývoji jednoho plasmoidu (yaWP - jestli ho někdo zná). Něco si najdu v tutoriálech, něco najdu v jiných programech a inspiruji se, zbytek metodou pokus-omyl. Nejhorší to bývá při překladu. Některé hlášky jsou docela zajímavé a co je vlastně špatně člověk většinou zjistí až s pomocí Googlu.
MainWindow::MainWindow() : m_dir(0)
). Podle me jsou dost dobre voleny na to, aby z nich bylo pekne jasne k cemu jednotlive Qt objekty slouzi a jak se s nimi delaji zakladni veci. Podle me je to pekny start pro programatory do Qt.
MainWindow::MainWindow() { m_dir = 0; ...m_dir jsem inicializoval, abych pak nemusel podmiňovat
delete
a mohl ho prostě spustit ať už se m_dir použije nebo ne. Je to bezpečnější.
NULL
ou Vetsina takovych IDE se da ovladat pouze intuici, neni treba nic studovat ani nic slozite nastavovat (mozna par cest). A ze jich neni malo, Qt Creator, KDevelop, QDevelop, Monkey Studio, HaiQ, Vim a urcite jsem jich dost zapomel. Zakladni schopnosti jako doplnovani kodu, editaci *.ui, kompilaci, debugovani, atd. podporuji svym zpusobem vsechny. Dobre IDE neznamena, ze se musi chovat a vypadat jako MSVS. Je treba vyzkouset vsechny a jit cestou nejmensiho odporu. Napr. u me je urcite neschudny vi, prestoze si jini bez nej nedokazi pocitac ani predstavit...
Když pochopíš princip, tak je i vim intuitivní.
dw - delete word
Nicméně netvrdím, že bych vim nějak extra uměl. Většinou se totiž pohybuji na různých AIX serverech, kde je jen vi, tak jsem se naučil jen pár základních příkazů, které potřebuji.
Ja a Vim nejsme kamaradi Ale pokud clovek ovlada Vim, verim, ze neni problem ho pouzivat i jako IDE pro Qt. (uz jsem tu par screenshotu videl)
Právě jsem na jeden narazil...
Možná mi někdo poradí. Tvrdě jsem narazil s naprostou trivialitou
Mám tři proměnné QColor, potřebuji je zazálohovat, změnit na default , něco vykreslit a pak obnovit ze zálohy. Bohužel to obnovení mi nějak nefunguje Zkoušel jsem různé varianty, studoval dokumentaci ke QColor, ale zatím nic nezabralo. Jak už jsem psal, v C++ celkem dost plavu
if ( m_theme != "default" && m_theme != "naked" ) { // set default colors when custom colors and not default or naked theme QColor fontColorBck = m_fontColor; QColor fontLowerColorBck = m_fontLowerColor; QColor fontShadowColorBck = m_fontShadowColor; setDefaultColors(); } ..... if ( m_theme != "default" && m_theme != "naked" ) { // restore font colors // tady mi to nějak drhnem_fontColor = fontColorBck; m_fontLowerColor = fontLowerColorBck; m_fontShadowColor = fontShadowColorBck; }
/usr/local/src/yawp/yawp/0.1/yawp.cpp: In member function ‘void YaWP::paintPanel(QPainter*, const QStyleOptionGraphicsItem*, const QRect&)’: /usr/local/src/yawp/yawp/0.1/yawp.cpp:781: error: ‘fontColorBck’ was not declared in this scope /usr/local/src/yawp/yawp/0.1/yawp.cpp:782: error: ‘fontLowerColorBck’ was not declared in this scope /usr/local/src/yawp/yawp/0.1/yawp.cpp:783: error: ‘fontShadowColorBck’ was not declared in this scope make[2]: *** [CMakeFiles/plasma_yawp.dir/yawp.o] Error 1 make[1]: *** [CMakeFiles/plasma_yawp.dir/all] Error 2 make: *** [all] Error 2
fontColorBck
, fontLowerColorBck
a fontShadowColorBck
jsou platné jenom v tom bloku if ( m_theme != "default" && m_theme != "naked" ) { ... }
. Nejpřímočařejší postup (netvrdím, že nejlepší) by byl asi takový:
QColor fontColorBck; QColor fontLowerColorBck; QColor fontShadowColorBck; if ( m_theme != "default" && m_theme != "naked" ) { // set default colors when custom colors and not default or naked theme fontColorBck = m_fontColor; fontLowerColorBck = m_fontLowerColor; fontShadowColorBck = m_fontShadowColor; setDefaultColors(); } ..... if ( m_theme != "default" && m_theme != "naked" ) { // restore font colors m_fontColor = fontColorBck; m_fontLowerColor = fontLowerColorBck; m_fontShadowColor = fontShadowColorBck; }Nejsa Céčkař, nejsem si jistý, jestli překladač nebude prudit, že ty proměnné might not be initialized, ale to je jen takový detail
Díky moc, na tohle jsem úplně zapomněl, už to funguje. Taková blbost a já se s tím od včerejška trápím.
To je tak, když člověk v něčem delší dobu nedělá, pak všechno zapomene
Constructs an invalid color with the RGB value (0, 0, 0). An invalid color is a color that is not properly set up for the underlying window system.
The alpha value of an invalid color is unspecified.
QStettings
jsem neznal, zajímavé. Dá se nastavit nějaká úplně jiná cesta k .conf
?
QSettings ( const QString & fileName, Format format, QObject * parent = 0 )
Mrkni na pretizene konstruktory, napr.:
QSettings::QSettings(const QString& fileName, Format format, QObject* parent = 0)
Na jednom tydennim oficialnim skoleni, na ktere jsem byl vyslan, se nam skolitel snazil mimo jineho vysvetlit, proc nepouzivat QtDesigner a proc radeji kreslit gui primo z kodu. Je pravda, ze designer nepodporuje spoustu veci, jako vlozeni na toolbar neco jineho nez toolbutton nebo akci z menu, obdobne se statusbarem, moznost rozdelit lokalizaci textu pro jednotne a mnozne cislo (pripadne vice tvaru mnozneho cisla (1 zprava, 2 zpravy, 5 zprav, ...)) nebo napr. pouziti tzv. stretch factoru...
Ale je pravda, ze stale pouzivam spise designer, protoze vyjma ruznych widgetu na tool/status-baru jsem zatim byl schopny vyjmenovane nevyhody elegantne obejit