Unterschiede zwischen Qt und wxWidgets

Qt und wxWidgets sind zwei beliebte Frameworks für die Entwicklung von Benutzeroberflächen, die sich in technischen und Lizenzunterschieden unterscheiden. Technisch gesehen basiert Qt auf einer objektorientierten Architektur mit einem eigenen Meta-Objekt-System (MOC), das Funktionen wie Signale und Slots für die Ereignisbehandlung bietet. Im Gegensatz dazu verwendet wxWidgets eine Wrapper-Architektur, die die nativen APIs der Zielplattform nutzt, was zu Anwendungen führt, die sich stärker an das native Look-and-Feel anpassen. In Bezug auf Programmiersprachen unterstützt Qt hauptsächlich C++, bietet aber auch Bindings für Sprachen wie Python (PyQt/PySide). wxWidgets ist primär für C++ konzipiert, hat aber ebenfalls Bindings für Python (wxPython) und Perl. Beim GUI-Design kommt Qt mit dem leistungsstarken Qt Designer zur visuellen Gestaltung von Benutzeroberflächen, während wxWidgets oft manuelles Codieren der GUI oder den Einsatz von Drittanbieter-Tools erfordert. In Bezug auf die Plattformunterstützung deckt Qt Windows, macOS, Linux sowie Embedded-Systeme und mobile Plattformen (Android, iOS) ab. wxWidgets unterstützt ebenfalls Windows, macOS und Linux, hat aber eingeschränkte Unterstützung für mobile Geräte.

In Bezug auf die Lizenzierung ist Qt unter GPL, LGPL und kommerziellen Lizenzen lizenziert. Die GPL erfordert die Offenlegung des Quellcodes von abgeleiteten Werken, während die LGPL eine flexiblere Nutzung ermöglicht, insbesondere für proprietäre Software, wenn dynamische Verlinkung verwendet wird. Unternehmen können auch eine kommerzielle Lizenz erwerben, um diese Einschränkungen zu umgehen. wxWidgets wird unter der wxWidgets-Lizenz veröffentlicht, die sehr liberal ist und ähnlich wie die LGPL funktioniert. Sie erlaubt die Entwicklung von sowohl Open-Source- als auch proprietärer Software, ohne die Notwendigkeit, den Quellcode offenzulegen.

Zusammenfassung der Unterschiede

  • Architektur:
    • Qt: Objektorientiert mit MOC, Signale und Slots.
    • wxWidgets: Wrapper-Architektur, nutzt native APIs.
  • Programmiersprachen:
    • Qt: Hauptsächlich C++, Bindings für Python und andere.
    • wxWidgets: Primär C++, Bindings für Python und Perl.
  • GUI-Design:
    • Qt: Qt Designer für visuelle Gestaltung.
    • wxWidgets: Oft manuelles Codieren oder Drittanbieter-Tools.
  • Plattformunterstützung:
    • Qt: Windows, macOS, Linux, Embedded, mobile (Android, iOS).
    • wxWidgets: Windows, macOS, Linux, eingeschränkte mobile Unterstützung.
  • Lizenz:
    • Qt: GPL, LGPL, kommerziell.
    • wxWidgets: Liberale wxWidgets-Lizenz, ähnlich LGPL.

wxWidgets-Tutorial 014: Überblick Event-Handling

In diesem Video zeige ich grob, wie das Event-Handling funktioniert. Tiefer gehen wir darauf aber dann bei den einzelnen Widgets ein.

Letztlich gibt es drei Varianten, wovon die dritte „deprecated“ ist und nicht mehr in neuen Programmen benutzt werden soll:

  1. Event-Table
  2. Bind
  3. Connect
Überblick über Event-Handling

Ein Screenshot unseres Beispielprogramms.

Screenshot unseres Beispielprogramms

Der Quelltext:

#include <wx/wx.h>

class MyApp : public wxApp {

	public:
		bool OnInit();

};

class MyFrame : public wxFrame {

	public:
		MyFrame();
	
	protected:
		void OnButtonClick(wxCommandEvent &event);

};

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit() {
	auto *myFrame = new MyFrame;
	myFrame->Show();

	SetTopWindow(myFrame);

	return true;
}

MyFrame::MyFrame() : wxFrame(nullptr, wxID_ANY, _("Events")) {
	wxButton *button = new wxButton(this, wxID_ANY, _("Click me"));

	button->Bind(wxEVT_BUTTON, &MyFrame::OnButtonClick, this);
}

void MyFrame::OnButtonClick(wxCommandEvent &event) {
	std::cout << "Button clicked" << std::endl;
}

Hier geht es zum Video.

wxWidgets-Tutorial 013: wxGridBagSizer

In diesem Video zeige ich, wie ein wxGridBagSizer funktioniert.

Der wxGridBagSizer basiert auf dem wxFlexGridSizer, bietet aber die Möglichkeit, Widgets und Sizer darin explizit zu positionieren und der Sizer kann Zellen zusammenführen.

Sizer (Layoutmanager): wxGridBagSizer

Hier ein Screenshot von unserem Beispielprogramm:

Screenshot des Beispielprogramms

Der Quelltext:

#include <wx/wx.h>
#include <wx/gbsizer.h>

class MyApp : public wxApp {

	public:
		bool OnInit();

};

class MyFrame : public wxFrame {

	public:
		MyFrame();

};

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit() {
	auto *myFrame = new MyFrame;
	myFrame->Show();

	SetTopWindow(myFrame);

	return true;
}

MyFrame::MyFrame() : wxFrame(nullptr, wxID_ANY, _("wxGridBagSizer")) {
	auto *mainPanel = new wxPanel(this);
	
	auto *gridBagSizer = new wxGridBagSizer(5, 5);

	wxGBSpan twoSpan(1, 2);

	gridBagSizer->Add(new wxStaticText(mainPanel, wxID_ANY, _("Firstname:")), wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_RIGHT);
	gridBagSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY), wxGBPosition(0, 1), twoSpan, wxEXPAND);

	gridBagSizer->Add(new wxStaticText(mainPanel, wxID_ANY, _("Lastname:")), wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_RIGHT);
	gridBagSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY), wxGBPosition(1, 1), twoSpan, wxEXPAND);

	gridBagSizer->Add(new wxStaticText(mainPanel, wxID_ANY, _("Age:")), wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_RIGHT);
	gridBagSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY), wxGBPosition(2, 1));

	gridBagSizer->Add(new wxStaticText(mainPanel, wxID_ANY, _("Zipcode/City:")), wxGBPosition(3, 0), wxDefaultSpan, wxALIGN_RIGHT);
	gridBagSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY), wxGBPosition(3, 1));
	gridBagSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY), wxGBPosition(3, 2), wxDefaultSpan, wxEXPAND);

	gridBagSizer->AddGrowableCol(2);

	mainPanel->SetSizer(gridBagSizer);
	gridBagSizer->SetSizeHints(this);
}

Hier geht es zum Video.

wxWidgets-Tutorial 012: wxSizer verschachteln

In diesem Video zeige ich, wie einfach es ist, wxSizer zu verschachteln.

Um komplexe GUIs zu entwickeln, ist es unabdingbar, dass man Sizer ineinander verschachteln kann. Damit lassen sich einfach und übersichtlich Formulare entwickeln, die dem Benutzer einen hohen Mehrwert bringen.

Sizer (Layoutmanager): wxSizer verschachteln

Hier ein Screenshot unseres Programms:

Screenshot von verschachtelten Sizern

Hier der Quelltext:

#include <wx/wx.h>

class MyApp : public wxApp {

	public:
		bool OnInit();

};

class MyFrame : public wxFrame {

	public:
		MyFrame();

};

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit() {
	auto *myFrame = new MyFrame;
	myFrame->Show();

	SetTopWindow(myFrame);

	return true;
}

MyFrame::MyFrame() : wxFrame(nullptr, wxID_ANY, _("Sizer in Sizers")) {
	auto *mainPanel = new wxPanel(this);

	auto *mainBoxSizer = new wxBoxSizer(wxHORIZONTAL);

	auto *flexGridSizer = new wxFlexGridSizer(2, 5, 5);

	flexGridSizer->AddGrowableCol(1);
	flexGridSizer->AddGrowableRow(4);

	flexGridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, _("Firstname:")), 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
	flexGridSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY), 0, wxEXPAND);

	flexGridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, _("Lastname:")), 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
	flexGridSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY), 0, wxEXPAND);

	flexGridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, _("Zipcode/City:")), 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);

	auto *addressSizer = new wxBoxSizer(wxHORIZONTAL);
	addressSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY));
	addressSizer->AddSpacer(5);
	addressSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY), 1);

	flexGridSizer->Add(addressSizer, 0, wxEXPAND);

	flexGridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, _("Age:")), 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
	flexGridSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY));

	flexGridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, _("Informations:")));
	flexGridSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY), 0, wxEXPAND);

	mainBoxSizer->Add(flexGridSizer, 1, wxEXPAND | wxALL, 15);

	mainPanel->SetSizer(mainBoxSizer);
	mainBoxSizer->SetSizeHints(this);
}

Hier geht es zum Video.

wxWidgets-Tutorial 011 – wxFlexGridSizer

In diesem Video zeige ich die Verwendung von wxFlexGridSizer.

Im Gegensatz zum wxBoxSizer, der Elemente nur horizontal oder vertikal ausrichten kann, dient der wxFlexGridSizer wie eine Tabelle, in der bestimmt werden kann, welche Spalten und Zeilen sich ausdehen durfen und in dem man einfach Formulare zusammensetzen kann.

Sizer (Layoutmanager): wxFlexGridSizer

Hier ein Screenshot unseres Programms:

Screenshot vom wxFlexGridSizer

Hier der Quelltext:

#include <wx/wx.h>

class MyApp : public wxApp {

	public:
		bool OnInit();

};

class MyFrame : public wxFrame {

	public:
		MyFrame();

};

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit() {
	auto *myFrame = new MyFrame;
	myFrame->Show();

	SetTopWindow(myFrame);

	return true;
}

MyFrame::MyFrame() : wxFrame(nullptr, wxID_ANY, _("wxFlexGridSizer")) {
	auto *mainPanel = new wxPanel(this);

	auto *flexGridSizer = new wxFlexGridSizer(2, 5, 5);

	flexGridSizer->AddGrowableCol(1);
	flexGridSizer->AddGrowableRow(3);

	flexGridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, _("Firstname:")), 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
	flexGridSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY), 0, wxEXPAND);

	flexGridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, _("Lastname:")), 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
	flexGridSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY), 0, wxEXPAND);

	flexGridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, _("Age:")), 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
	flexGridSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY));

	flexGridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, _("Informations:")));
	flexGridSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY), 0, wxEXPAND);

	mainPanel->SetSizer(flexGridSizer);
	flexGridSizer->SetSizeHints(this);
}

Hier geht es zum Video.

wxWidgets-Tutorial 010 – wxBoxSizer

In diesem Video beginnen wir mit Sizern, im Speziellen mit wxBoxSizer.

Layoutmanager sind essentiell bei der Programmierung von grafischen Benutzeroberflächen. Gab es zu Beginn der grafischen Benutzeroberflächen teils nur die Möglichkeit, Elemente absolut positioniert zu platzieren, bieten Layoutmanager, bei wxWidgets Sizer genannt, die Möglichkeit, die Ausrichtung und Anordnung dynamisch zu gestalten.

Der wxBoxSizer kann Elemente horizontal oder vertikal anordnen, proportional vergrößern und verkleiner, ausrichten und vieles mehr.

Sizer (Layoutmanager): wxBoxSizer

Hier ein Screenshot unseres Programms:

Screenshot mit einem wxBoxSizer

Hier der Quelltext:

#include <wx/wx.h>

class MyApp : public wxApp {

	public:
		bool OnInit();

};

class MyFrame : public wxFrame {

	public:
		MyFrame();

};

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit() {
	auto *myFrame = new MyFrame;
	myFrame->Show();

	SetTopWindow(myFrame);

	return true;
}

MyFrame::MyFrame() : wxFrame(nullptr, wxID_ANY, _("wxBoxSizer")) {
	auto *mainPanel = new wxPanel(this);
	auto *mainBoxSizer = new wxBoxSizer(wxHORIZONTAL); // wxVERTICAL

	mainBoxSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY, _("Eingabefeld 1")), 1, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 5);
	mainBoxSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY, _("Eingabefeld 2")), 2, wxEXPAND | wxALL, 5);
	mainBoxSizer->AddStretchSpacer();
	mainBoxSizer->Add(new wxTextCtrl(mainPanel, wxID_ANY, _("Eingabefeld 3")), 1, wxEXPAND | wxRIGHT | wxTOP | wxBOTTOM, 5);


	auto *tmp = new wxTextCtrl(mainPanel, wxID_ANY, _("Eingabefeld 0"));
	mainBoxSizer->Insert(0, tmp, 1, wxEXPAND | wxRIGHT | wxTOP | wxBOTTOM, 5);
	mainBoxSizer->InsertSpacer(0, 50);

	mainBoxSizer->Detach(1);
	tmp->Destroy();


	mainPanel->SetSizer(mainBoxSizer);
	mainBoxSizer->SetSizeHints(this);

	std::cout << "Element count: " << mainBoxSizer->GetItemCount() << std::endl;
	std::cout << "Position: " << mainBoxSizer->GetPosition().x << "x" << mainBoxSizer->GetPosition().y << std::endl;
	std::cout << "Size: " << mainBoxSizer->GetSize().GetWidth() << "x" << mainBoxSizer->GetSize().GetHeight() << std::endl;
}

Hier geht es zum Video.

Qt-Tutorial 042: QStatusBar

In diesem Video zeige ich, wie man mit der Statusbar (QStatusBar) umgehen kann.

Viele Fenster des benutzten Fenstermanagers haben am unteren Rand eine Leiste, die manchmal einfach nur da ist, manchmal Informationen anzeigt, manchmal aber auch Interaktionen anbietet. Dieses Video zeigt, wie man Informationen dauerhaft oder für eine gewisse Zeit anzeigt oder Widgets hinzufügt.

QStatusBar

Hier ein Bild unseres Programms:

Screenshot von unserem Beispielprogramm mit QStatusBar

Hier geht es zum Video.

Bald neue Videos

Viele haben mir geschrieben, dass ich doch weitere Videos bzw. Tutorials machen soll. Das freut mich sehr.

Zur Zeit nimmt mich die neue Arbeitstelle und meine Familie gut ein, ich habe aber schon die nächsten Videos geplant (Themen: wxWidgets, Qt und auch FreeBSD) und freue mich, sie bald machen und veröffentlichen zu können. Es dauert allerdings noch ein paar Tage. Aber: Es wird mit den Tutorials weiter gehen.

Wenn ihr Vorschläge für bestimmte Themen habt, gerne her damit.

compow als Privatprojekt in Form einer Referenz wieder online

Eines meiner Projekte, dass ich vor wenigen Jahren gemacht hatte, lag noch auf meiner Festplatte und war bereits lange nicht mehr aktiv. Ich dachte mir allerdings, dass ich das noch einmal gerne als Referenz von mir online stellen wollte: compow.

Bei compow handelt es sich um eine Website, auf der sich Firmen vorstellen können und Stellenanzeigen schalten können. Ursprünglich war das mal kostenpflichtig, was ich aber herausgenommen habe, da ich nicht selbständig bin und damit kein Geld verdiene, es ist lediglich eine meiner Referenzen.

Das Interessante an der Website ist der Tech-Stack, denn anstelle einer der üblichen Webprogrammiersprachen wie Ruby, PHP, Python, Go, ASP.NET (keine Sprache, aber ihr wisst, was ich meine), basiert diese Website auf folgenden Technologien:

Wie gesagt, die Seite dient einfach nur als Referenz, womit ich mich in den letzten Jahren beschäftigte. Die Website ist nicht weiterentwickelt und wird es mitunter auch nicht.