wxWidgets
C++用のクロスプラットフォームGUIライブラリ。各プラットフォームのネイティブAPIを使用し、OS標準の外観と操作感を実現。軽量で高速、商用利用も可能なライセンス。長期間にわたる安定したAPI提供。
GitHub概要
wxWidgets/wxWidgets
Cross-Platform C++ GUI Library
スター6,702
ウォッチ254
フォーク1,826
作成日:2011年5月18日
言語:C++
ライセンス:-
トピックス
c-plus-pluscocoacross-platformcross-platform-desktopdesktopgtkguigui-frameworklinuxmacosportablewin32windowswxwidgetsx11
スター履歴
データ取得日時: 2025/7/15 22:54
デスクトップフレームワーク
wxWidgets
概要
wxWidgetsは、C++で書かれたクロスプラットフォームGUIライブラリです。ネイティブな見た目と動作を提供し、Windows、macOS、Linux(GTK)、その他多くのプラットフォームで動作します。1992年から開発されており、安定性と互換性で定評があります。
詳細
wxWidgetsは各プラットフォームのネイティブAPIを直接使用するため、OSごとに自然な見た目とユーザビリティを実現できます。WindowsではWin32 API、macOSではCocoa、LinuxでGTKを使用し、真にクロスプラットフォームなアプリケーションを構築できます。豊富なUIコントロールとレイアウト管理機能を提供し、エンタープライズレベルのアプリケーション開発に適しています。
特徴
- ネイティブ外観: 各プラットフォームでネイティブな見た目と動作
- 広範囲なプラットフォーム対応: Windows、macOS、Linux、FreeBSD、Solarisなど
- 豊富なコントロール: ボタン、リスト、ツリー、グリッド、メニューなど
- オープンソース: wxWindows Library Licenceの下で利用可能
- 長期安定性: 30年以上の開発実績
- Python bindings: wxPython経由でPythonからも利用可能
アーキテクチャ
- MVC対応: Document/Viewアーキテクチャのサポート
- イベント駆動: コールバックではなくイベントベースの設計
- メモリ管理: 自動的なメモリ管理とリソース解放
- 国際化: Unicode対応と多言語サポート
- プリンティング: 高品質な印刷機能
メリット・デメリット
メリット
- ネイティブな見た目でOSに自然に統合される
- 非常に安定したライブラリで長期サポートが期待できる
- 豊富なドキュメントとサンプルコード
- 大規模なコミュニティとエコシステム
- エンタープライズアプリケーションでの実績
- Pythonバインディング(wxPython)も利用可能
デメリット
- 学習コストが高く、API が複雑
- モダンなUI/UX設計には向かない
- C++特有の複雑性(メモリ管理、コンパイラ依存)
- 新しいUIトレンドへの対応が遅い
- バンドルサイズが大きくなりがち
参考ページ
書き方の例
Hello World
#include <wx/wx.h>
class MyApp : public wxApp
{
public:
bool OnInit() override;
};
class MyFrame : public wxFrame
{
public:
MyFrame();
private:
void OnExit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
};
wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit()
{
MyFrame *frame = new MyFrame();
frame->Show(true);
return true;
}
MyFrame::MyFrame()
: wxFrame(nullptr, wxID_ANY, "Hello wxWidgets")
{
CreateStatusBar();
SetStatusText("Welcome to wxWidgets!");
}
ウィンドウとコントロール
class MainFrame : public wxFrame
{
public:
MainFrame() : wxFrame(nullptr, wxID_ANY, "wxWidgets App")
{
// メニューバー
wxMenuBar* menuBar = new wxMenuBar();
wxMenu* fileMenu = new wxMenu();
fileMenu->Append(wxID_EXIT, "&Exit");
menuBar->Append(fileMenu, "&File");
SetMenuBar(menuBar);
// メインパネル
wxPanel* panel = new wxPanel(this);
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
// コントロール
wxStaticText* label = new wxStaticText(panel, wxID_ANY, "Hello World!");
wxTextCtrl* textCtrl = new wxTextCtrl(panel, wxID_ANY, "");
wxButton* button = new wxButton(panel, wxID_ANY, "Click Me");
// レイアウト
sizer->Add(label, 0, wxALL, 5);
sizer->Add(textCtrl, 0, wxALL | wxEXPAND, 5);
sizer->Add(button, 0, wxALL, 5);
panel->SetSizer(sizer);
// イベントハンドラー
button->Bind(wxEVT_COMMAND_BUTTON_CLICKED,
[this](wxCommandEvent&) {
wxMessageBox("Button clicked!", "Info");
});
}
};
イベント処理とダイアログ
class EventFrame : public wxFrame
{
public:
EventFrame() : wxFrame(nullptr, wxID_ANY, "Event Handling")
{
wxPanel* panel = new wxPanel(this);
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
wxButton* dialogBtn = new wxButton(panel, wxID_ANY, "Show Dialog");
wxButton* fileBtn = new wxButton(panel, wxID_ANY, "Open File");
wxButton* exitBtn = new wxButton(panel, wxID_ANY, "Exit");
sizer->Add(dialogBtn, 0, wxALL, 5);
sizer->Add(fileBtn, 0, wxALL, 5);
sizer->Add(exitBtn, 0, wxALL, 5);
panel->SetSizer(sizer);
// イベントバインド
dialogBtn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &EventFrame::OnDialog, this);
fileBtn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &EventFrame::OnOpenFile, this);
exitBtn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &EventFrame::OnExit, this);
}
private:
void OnDialog(wxCommandEvent& event)
{
wxMessageDialog dlg(this, "This is a message dialog", "Information",
wxOK | wxICON_INFORMATION);
dlg.ShowModal();
}
void OnOpenFile(wxCommandEvent& event)
{
wxFileDialog dlg(this, "Choose a file", "", "",
"Text files (*.txt)|*.txt|All files (*.*)|*.*",
wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if (dlg.ShowModal() == wxID_OK)
{
wxString path = dlg.GetPath();
wxMessageBox("Selected: " + path, "File Selected");
}
}
void OnExit(wxCommandEvent& event)
{
Close(true);
}
};
リストとグリッド
class ListFrame : public wxFrame
{
public:
ListFrame() : wxFrame(nullptr, wxID_ANY, "List and Grid")
{
wxPanel* panel = new wxPanel(this);
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
// リストコントロール
wxListCtrl* listCtrl = new wxListCtrl(panel, wxID_ANY,
wxDefaultPosition, wxDefaultSize,
wxLC_REPORT | wxLC_SINGLE_SEL);
// カラム追加
listCtrl->AppendColumn("Name", wxLIST_FORMAT_LEFT, 100);
listCtrl->AppendColumn("Age", wxLIST_FORMAT_RIGHT, 60);
listCtrl->AppendColumn("City", wxLIST_FORMAT_LEFT, 120);
// データ追加
long index = listCtrl->InsertItem(0, "John Doe");
listCtrl->SetItem(index, 1, "30");
listCtrl->SetItem(index, 2, "New York");
index = listCtrl->InsertItem(1, "Jane Smith");
listCtrl->SetItem(index, 1, "25");
listCtrl->SetItem(index, 2, "Los Angeles");
// グリッド(要wxGrid include)
wxGrid* grid = new wxGrid(panel, wxID_ANY);
grid->CreateGrid(5, 3);
grid->SetColLabelValue(0, "Product");
grid->SetColLabelValue(1, "Price");
grid->SetColLabelValue(2, "Stock");
// グリッドデータ
grid->SetCellValue(0, 0, "Laptop");
grid->SetCellValue(0, 1, "$999");
grid->SetCellValue(0, 2, "10");
sizer->Add(listCtrl, 1, wxALL | wxEXPAND, 5);
sizer->Add(grid, 1, wxALL | wxEXPAND, 5);
panel->SetSizer(sizer);
}
};
マルチスレッドとタイマー
class TimerFrame : public wxFrame
{
public:
TimerFrame() : wxFrame(nullptr, wxID_ANY, "Timer Example"),
timer(this, wxID_ANY)
{
wxPanel* panel = new wxPanel(this);
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
timeLabel = new wxStaticText(panel, wxID_ANY, "00:00:00");
wxButton* startBtn = new wxButton(panel, wxID_ANY, "Start Timer");
wxButton* stopBtn = new wxButton(panel, wxID_ANY, "Stop Timer");
sizer->Add(timeLabel, 0, wxALL | wxCENTER, 10);
sizer->Add(startBtn, 0, wxALL, 5);
sizer->Add(stopBtn, 0, wxALL, 5);
panel->SetSizer(sizer);
// イベントバインド
startBtn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &TimerFrame::OnStart, this);
stopBtn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &TimerFrame::OnStop, this);
timer.Bind(wxEVT_TIMER, &TimerFrame::OnTimer, this);
startTime = wxDateTime::Now();
}
private:
wxTimer timer;
wxStaticText* timeLabel;
wxDateTime startTime;
void OnStart(wxCommandEvent& event)
{
startTime = wxDateTime::Now();
timer.Start(1000); // 1秒間隔
}
void OnStop(wxCommandEvent& event)
{
timer.Stop();
}
void OnTimer(wxTimerEvent& event)
{
wxDateTime now = wxDateTime::Now();
wxTimeSpan diff = now - startTime;
timeLabel->SetLabel(diff.Format("%H:%M:%S"));
}
};
カスタム描画
class DrawingPanel : public wxPanel
{
public:
DrawingPanel(wxFrame* parent) : wxPanel(parent)
{
Bind(wxEVT_PAINT, &DrawingPanel::OnPaint, this);
Bind(wxEVT_LEFT_DOWN, &DrawingPanel::OnMouseDown, this);
}
private:
std::vector<wxPoint> points;
void OnPaint(wxPaintEvent& event)
{
wxPaintDC dc(this);
// 背景をクリア
dc.Clear();
// グラデーション
wxRect rect = GetClientRect();
dc.GradientFillLinear(rect, wxColour(200, 200, 255),
wxColour(100, 100, 200), wxSOUTH);
// 円と線を描画
dc.SetPen(wxPen(wxColour(255, 0, 0), 3));
dc.SetBrush(wxBrush(wxColour(0, 255, 0, 128)));
for (size_t i = 0; i < points.size(); ++i)
{
dc.DrawCircle(points[i], 20);
if (i > 0)
{
dc.DrawLine(points[i-1], points[i]);
}
}
// テキスト描画
dc.SetTextForeground(wxColour(0, 0, 0));
dc.DrawText(wxString::Format("Points: %zu", points.size()), 10, 10);
}
void OnMouseDown(wxMouseEvent& event)
{
points.push_back(event.GetPosition());
Refresh(); // 再描画をトリガー
}
};