概要
本記事は、富途牛牛風取引ツールのUIをQtで再現するシリーズの第3回目です。前回までは機能面(タブのドラッグ・削除、磁力吸着など)に焦点を当てていましたが、UIは非常に素朴な見た目でした。今回は全体的な見た目の改善を中心に、QSSによるスタイリングや動的プロパティを活用したインタラクティブなデザインを紹介します。
UI改善のポイント
主な改善対象は以下の通りです:
- ツールボックスのレイアウトと視覚デザイン
- カスタムタブバーのホバー・選択状態の表現
- サブウィンドウのフォーカス状態に応じた枠線変更
ツールボックスの実装
レイアウト構成
ツールボックスはタイトルバーとクライアント領域の2つのセクションで構成されます。
- タイトルバー:ウィンドウの識別名表示、ドラッグ移動、閉じるボタンを備える
- クライアント領域:
QTabWidget内にQListWidgetを配置し、アイコンモードでツールボタンを表示
コード例:ツールリスト初期化
void ToolBoxDialog::InitializeTools(int start, int end, const QString& title) {
auto* listWidget = new QListWidget(this);
listWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
listWidget->setViewMode(QListView::IconMode);
listWidget->setResizeMode(QListView::Adjust);
listWidget->setSpacing(3);
listWidget->setDragEnabled(false);
connect(listWidget, &QListWidget::itemClicked, this, &ToolBoxDialog::OnToolSelected);
for (int i = start; i < end; ++i) {
listWidget->addItem(CreateToolItem(toolNames[i], toolTypes[i]));
}
m_tabWidget->addTab(listWidget, title);
}
アイテム生成ロジック
QListWidgetItem* CreateToolItem(const QString& name, ToolType type) {
auto* item = new QListWidgetItem;
item->setSizeHint(QSize(72, 72));
item->setFlags(item->flags() & ~Qt::ItemIsSelectable);
item->setText(name);
item->setData(Qt::UserRole, static_cast<int>(type));
item->setIcon(QIcon(QStringLiteral("./image/mainWindow/tquant-btn_normal.png")));
return item;
}
カスタムタブバーのスタイリング
Qtの動的プロパティ機能を活用し、マウスオーバー時にテキスト色を変更しています。
void CustomTabButton::enterEvent(QEvent* event) {
m_label->setProperty("Hovered", true);
m_label->style()->unpolish(m_label);
m_label->style()->polish(m_label);
QWidget::enterEvent(event);
}
フォーカス状態の可視化
サブウィンドウがフォーカスを得た際に黄色い枠線を表示する仕組みです。
void SubWindow::focusInEvent(QFocusEvent* event) {
setProperty("HasFocus", true);
style()->unpolish(this);
style()->polish(this);
QWidget::focusInEvent(event);
}
void SubWindow::focusOutEvent(QFocusEvent* event) {
setProperty("HasFocus", false);
style()->unpolish(this);
style()->polish(this);
QWidget::focusOutEvent(event);
}
QSSスタイルシート
QWidget {
background: #28323f;
color: #DDDDDD;
}
SubWindow {
border: 1px solid #474F57;
background: #1D2224;
}
SubWindow[HasFocus="true"] {
border: 2px solid #FFE100;
}
CustomTabButton:hover {
border-bottom: 1px solid #FFB700;
}
CustomTabButton[Selected="true"] {
border-bottom: 1px solid #FF9900;
color: #FF9900;
}
CustomTabButton QLabel[Hovered="true"] {
color: #FF9900;
}
QTabBar::tab {
background: #1D2224;
border-bottom: 1px solid #2B3236;
min-width: 20ex;
padding: 4px;
color: #919AA3;
}
QTabBar::tab:selected {
border-bottom: 1px solid #FF9900;
}
QTabBar::tab:hover {
border-bottom: 1px solid #FFB700;
}
QListView {
border: none;
margin: 12px;
outline: none;
}
QListView::item {
padding-top: 10px;
border: 1px solid transparent;
}
QListView::item:hover {
color: #FF9900;
background: #6B7276;
}
QSSファイルの読み込み
void LoadStyleSheet(QApplication& app, const QString& filePath) {
QFile file(filePath);
if (file.open(QFile::ReadOnly)) {
QString styleSheet = QLatin1String(file.readAll());
app.setStyleSheet(styleSheet);
file.close();
}
}
大規模なアプリケーションでは、スタイルシートをコンポーネント単位または機能単位で分割して管理することを推奨します。