6.5.3 clean

This commit is contained in:
kleuter
2023-11-01 18:02:52 +01:00
parent bbe896803b
commit 7018d9e6c8
2170 changed files with 57471 additions and 43550 deletions

View File

@ -0,0 +1,59 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(dockwidgets LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/mainwindows/dockwidgets")
find_package(Qt6
REQUIRED COMPONENTS Core Gui Widgets
OPTIONAL_COMPONENTS PrintSupport
)
qt_standard_project_setup()
qt_add_executable(dockwidgets
main.cpp
mainwindow.cpp mainwindow.h
)
set_target_properties(dockwidgets PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(dockwidgets PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
if (TARGET Qt6::PrintSupport)
target_link_libraries(dockwidgets PRIVATE Qt6::PrintSupport)
endif()
# Resources:
set(dockwidgets_resource_files
"images/new.png"
"images/print.png"
"images/save.png"
"images/undo.png"
)
qt_add_resources(dockwidgets "dockwidgets"
PREFIX
"/"
FILES
${dockwidgets_resource_files}
)
install(TARGETS dockwidgets
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,12 @@
QT += widgets
requires(qtConfig(listwidget))
qtHaveModule(printsupport): QT += printsupport
HEADERS = mainwindow.h
SOURCES = main.cpp \
mainwindow.cpp
RESOURCES = dockwidgets.qrc
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/mainwindows/dockwidgets
INSTALLS += target

View File

@ -0,0 +1,8 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>images/new.png</file>
<file>images/print.png</file>
<file>images/save.png</file>
<file>images/undo.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 977 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,14 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mainWin;
mainWin.show();
return app.exec();
}

View File

@ -0,0 +1,298 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
#include <QtWidgets>
#if defined(QT_PRINTSUPPORT_LIB)
#include <QtPrintSupport/qtprintsupportglobal.h>
#if QT_CONFIG(printdialog)
#include <QtPrintSupport>
#endif
#endif
#include "mainwindow.h"
//! [0]
//! [1]
MainWindow::MainWindow()
: textEdit(new QTextEdit)
{
setCentralWidget(textEdit);
createActions();
createStatusBar();
createDockWindows();
setWindowTitle(tr("Dock Widgets"));
newLetter();
setUnifiedTitleAndToolBarOnMac(true);
}
//! [1]
//! [2]
void MainWindow::newLetter()
{
textEdit->clear();
QTextCursor cursor(textEdit->textCursor());
cursor.movePosition(QTextCursor::Start);
QTextFrame *topFrame = cursor.currentFrame();
QTextFrameFormat topFrameFormat = topFrame->frameFormat();
topFrameFormat.setPadding(16);
topFrame->setFrameFormat(topFrameFormat);
QTextCharFormat textFormat;
QTextCharFormat boldFormat;
boldFormat.setFontWeight(QFont::Bold);
QTextCharFormat italicFormat;
italicFormat.setFontItalic(true);
QTextTableFormat tableFormat;
tableFormat.setBorder(1);
tableFormat.setCellPadding(16);
tableFormat.setAlignment(Qt::AlignRight);
cursor.insertTable(1, 1, tableFormat);
cursor.insertText("The Firm", boldFormat);
cursor.insertBlock();
cursor.insertText("321 City Street", textFormat);
cursor.insertBlock();
cursor.insertText("Industry Park");
cursor.insertBlock();
cursor.insertText("Some Country");
cursor.setPosition(topFrame->lastPosition());
cursor.insertText(QDate::currentDate().toString("d MMMM yyyy"), textFormat);
cursor.insertBlock();
cursor.insertBlock();
cursor.insertText("Dear ", textFormat);
cursor.insertText("NAME", italicFormat);
cursor.insertText(",", textFormat);
for (int i = 0; i < 3; ++i)
cursor.insertBlock();
cursor.insertText(tr("Yours sincerely,"), textFormat);
for (int i = 0; i < 3; ++i)
cursor.insertBlock();
cursor.insertText("The Boss", textFormat);
cursor.insertBlock();
cursor.insertText("ADDRESS", italicFormat);
}
//! [2]
//! [3]
void MainWindow::print()
{
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog)
QTextDocument *document = textEdit->document();
QPrinter printer;
QPrintDialog dlg(&printer, this);
if (dlg.exec() != QDialog::Accepted) {
return;
}
document->print(&printer);
statusBar()->showMessage(tr("Ready"), 2000);
#endif
}
//! [3]
//! [4]
void MainWindow::save()
{
QMimeDatabase mimeDatabase;
QString fileName = QFileDialog::getSaveFileName(this,
tr("Choose a file name"), ".",
mimeDatabase.mimeTypeForName("text/html").filterString());
if (fileName.isEmpty())
return;
QFile file(fileName);
if (!file.open(QFile::WriteOnly | QFile::Text)) {
QMessageBox::warning(this, tr("Dock Widgets"),
tr("Cannot write file %1:\n%2.")
.arg(QDir::toNativeSeparators(fileName), file.errorString()));
return;
}
QTextStream out(&file);
QGuiApplication::setOverrideCursor(Qt::WaitCursor);
out << textEdit->toHtml();
QGuiApplication::restoreOverrideCursor();
statusBar()->showMessage(tr("Saved '%1'").arg(fileName), 2000);
}
//! [4]
//! [5]
void MainWindow::undo()
{
QTextDocument *document = textEdit->document();
document->undo();
}
//! [5]
//! [6]
void MainWindow::insertCustomer(const QString &customer)
{
if (customer.isEmpty())
return;
QStringList customerList = customer.split(", ");
QTextDocument *document = textEdit->document();
QTextCursor cursor = document->find("NAME");
if (!cursor.isNull()) {
cursor.beginEditBlock();
cursor.insertText(customerList.at(0));
QTextCursor oldcursor = cursor;
cursor = document->find("ADDRESS");
if (!cursor.isNull()) {
for (int i = 1; i < customerList.size(); ++i) {
cursor.insertBlock();
cursor.insertText(customerList.at(i));
}
cursor.endEditBlock();
}
else
oldcursor.endEditBlock();
}
}
//! [6]
//! [7]
void MainWindow::addParagraph(const QString &paragraph)
{
if (paragraph.isEmpty())
return;
QTextDocument *document = textEdit->document();
QTextCursor cursor = document->find(tr("Yours sincerely,"));
if (cursor.isNull())
return;
cursor.beginEditBlock();
cursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::MoveAnchor, 2);
cursor.insertBlock();
cursor.insertText(paragraph);
cursor.insertBlock();
cursor.endEditBlock();
}
//! [7]
void MainWindow::about()
{
QMessageBox::about(this, tr("About Dock Widgets"),
tr("The <b>Dock Widgets</b> example demonstrates how to "
"use Qt's dock widgets. You can enter your own text, "
"click a customer to add a customer name and "
"address, and click standard paragraphs to add them."));
}
void MainWindow::createActions()
{
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
QToolBar *fileToolBar = addToolBar(tr("File"));
const QIcon newIcon = QIcon::fromTheme("document-new", QIcon(":/images/new.png"));
QAction *newLetterAct = new QAction(newIcon, tr("&New Letter"), this);
newLetterAct->setShortcuts(QKeySequence::New);
newLetterAct->setStatusTip(tr("Create a new form letter"));
connect(newLetterAct, &QAction::triggered, this, &MainWindow::newLetter);
fileMenu->addAction(newLetterAct);
fileToolBar->addAction(newLetterAct);
const QIcon saveIcon = QIcon::fromTheme("document-save", QIcon(":/images/save.png"));
QAction *saveAct = new QAction(saveIcon, tr("&Save..."), this);
saveAct->setShortcuts(QKeySequence::Save);
saveAct->setStatusTip(tr("Save the current form letter"));
connect(saveAct, &QAction::triggered, this, &MainWindow::save);
fileMenu->addAction(saveAct);
fileToolBar->addAction(saveAct);
const QIcon printIcon = QIcon::fromTheme("document-print", QIcon(":/images/print.png"));
QAction *printAct = new QAction(printIcon, tr("&Print..."), this);
printAct->setShortcuts(QKeySequence::Print);
printAct->setStatusTip(tr("Print the current form letter"));
connect(printAct, &QAction::triggered, this, &MainWindow::print);
fileMenu->addAction(printAct);
fileToolBar->addAction(printAct);
fileMenu->addSeparator();
QAction *quitAct = fileMenu->addAction(tr("&Quit"), qApp, &QCoreApplication::quit);
quitAct->setShortcuts(QKeySequence::Quit);
quitAct->setStatusTip(tr("Quit the application"));
QMenu *editMenu = menuBar()->addMenu(tr("&Edit"));
QToolBar *editToolBar = addToolBar(tr("Edit"));
const QIcon undoIcon = QIcon::fromTheme("edit-undo", QIcon(":/images/undo.png"));
QAction *undoAct = new QAction(undoIcon, tr("&Undo"), this);
undoAct->setShortcuts(QKeySequence::Undo);
undoAct->setStatusTip(tr("Undo the last editing action"));
connect(undoAct, &QAction::triggered, this, &MainWindow::undo);
editMenu->addAction(undoAct);
editToolBar->addAction(undoAct);
viewMenu = menuBar()->addMenu(tr("&View"));
menuBar()->addSeparator();
QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
QAction *aboutAct = helpMenu->addAction(tr("&About"), this, &MainWindow::about);
aboutAct->setStatusTip(tr("Show the application's About box"));
QAction *aboutQtAct = helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt);
aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
}
//! [8]
void MainWindow::createStatusBar()
{
statusBar()->showMessage(tr("Ready"));
}
//! [8]
//! [9]
void MainWindow::createDockWindows()
{
QDockWidget *dock = new QDockWidget(tr("Customers"), this);
dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
customerList = new QListWidget(dock);
customerList->addItems(QStringList()
<< "John Doe, Harmony Enterprises, 12 Lakeside, Ambleton"
<< "Jane Doe, Memorabilia, 23 Watersedge, Beaton"
<< "Tammy Shea, Tiblanka, 38 Sea Views, Carlton"
<< "Tim Sheen, Caraba Gifts, 48 Ocean Way, Deal"
<< "Sol Harvey, Chicos Coffee, 53 New Springs, Eccleston"
<< "Sally Hobart, Tiroli Tea, 67 Long River, Fedula");
dock->setWidget(customerList);
addDockWidget(Qt::RightDockWidgetArea, dock);
viewMenu->addAction(dock->toggleViewAction());
dock = new QDockWidget(tr("Paragraphs"), this);
paragraphsList = new QListWidget(dock);
paragraphsList->addItems(QStringList()
<< "Thank you for your payment which we have received today."
<< "Your order has been dispatched and should be with you "
"within 28 days."
<< "We have dispatched those items that were in stock. The "
"rest of your order will be dispatched once all the "
"remaining items have arrived at our warehouse. No "
"additional shipping charges will be made."
<< "You made a small overpayment (less than $5) which we "
"will keep on account for you, or return at your request."
<< "You made a small underpayment (less than $1), but we have "
"sent your order anyway. We'll add this underpayment to "
"your next bill."
<< "Unfortunately you did not send enough money. Please remit "
"an additional $. Your order will be dispatched as soon as "
"the complete amount has been received."
<< "You made an overpayment (more than $5). Do you wish to "
"buy more items, or should we return the excess to you?");
dock->setWidget(paragraphsList);
addDockWidget(Qt::RightDockWidgetArea, dock);
viewMenu->addAction(dock->toggleViewAction());
connect(customerList, &QListWidget::currentTextChanged,
this, &MainWindow::insertCustomer);
connect(paragraphsList, &QListWidget::currentTextChanged,
this, &MainWindow::addParagraph);
}
//! [9]

View File

@ -0,0 +1,46 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
class QAction;
class QListWidget;
class QMenu;
class QTextEdit;
QT_END_NAMESPACE
//! [0]
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
private slots:
void newLetter();
void save();
void print();
void undo();
void about();
void insertCustomer(const QString &customer);
void addParagraph(const QString &paragraph);
private:
void createActions();
void createStatusBar();
void createDockWindows();
QTextEdit *textEdit;
QListWidget *customerList;
QListWidget *paragraphsList;
QMenu *viewMenu;
};
//! [0]
#endif

View File

@ -0,0 +1,54 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(mainwindow LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/mainwindows/mainwindow")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(mainwindow
colorswatch.cpp colorswatch.h
main.cpp
mainwindow.cpp mainwindow.h
toolbar.cpp toolbar.h
)
set_target_properties(mainwindow PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(mainwindow PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
# Resources:
set(mainwindow_resource_files
"qt.png"
"titlebarCenter.png"
"titlebarLeft.png"
"titlebarRight.png"
)
qt_add_resources(mainwindow "mainwindow"
PREFIX
"/res"
FILES
${mainwindow_resource_files}
)
install(TARGETS mainwindow
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,685 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "colorswatch.h"
#include <QActionGroup>
#include <QtEvents>
#include <QFrame>
#include <QMainWindow>
#include <QMenu>
#include <QPainter>
#include <QImage>
#include <QColor>
#include <QDialog>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QSignalBlocker>
#include <QSpinBox>
#include <QLabel>
#include <QPainterPath>
#include <QPushButton>
#include <QHBoxLayout>
#include <QBitmap>
#include <QtDebug>
#undef DEBUG_SIZEHINTS
QColor bgColorForName(const QString &name)
{
if (name == "Black")
return QColor("#D8D8D8");
if (name == "White")
return QColor("#F1F1F1");
if (name == "Red")
return QColor("#F1D8D8");
if (name == "Green")
return QColor("#D8E4D8");
if (name == "Blue")
return QColor("#D8D8F1");
if (name == "Yellow")
return QColor("#F1F0D8");
return QColor(name).lighter(110);
}
QColor fgColorForName(const QString &name)
{
if (name == "Black")
return QColor("#6C6C6C");
if (name == "White")
return QColor("#F8F8F8");
if (name == "Red")
return QColor("#F86C6C");
if (name == "Green")
return QColor("#6CB26C");
if (name == "Blue")
return QColor("#6C6CF8");
if (name == "Yellow")
return QColor("#F8F76C");
return QColor(name);
}
class ColorDock : public QFrame
{
Q_OBJECT
public:
explicit ColorDock(const QString &c, QWidget *parent);
QSize sizeHint() const override { return szHint; }
QSize minimumSizeHint() const override { return minSzHint; }
void setCustomSizeHint(const QSize &size);
public slots:
void changeSizeHints();
protected:
void paintEvent(QPaintEvent *) override;
private:
const QString color;
QSize szHint;
QSize minSzHint;
};
ColorDock::ColorDock(const QString &c, QWidget *parent)
: QFrame(parent)
, color(c)
, szHint(-1, -1)
, minSzHint(125, 75)
{
QFont font = this->font();
font.setPointSize(8);
setFont(font);
}
void ColorDock::paintEvent(QPaintEvent *)
{
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
p.fillRect(rect(), bgColorForName(color));
p.save();
extern void render_qt_text(QPainter *, int, int, const QColor &);
render_qt_text(&p, width(), height(), fgColorForName(color));
p.restore();
#ifdef DEBUG_SIZEHINTS
p.setRenderHint(QPainter::Antialiasing, false);
QSize sz = size();
QSize szHint = sizeHint();
QSize minSzHint = minimumSizeHint();
QSize maxSz = maximumSize();
QString text = QString::fromLatin1("sz: %1x%2\nszHint: %3x%4\nminSzHint: %5x%6\n"
"maxSz: %8x%9")
.arg(sz.width()).arg(sz.height())
.arg(szHint.width()).arg(szHint.height())
.arg(minSzHint.width()).arg(minSzHint.height())
.arg(maxSz.width()).arg(maxSz.height());
QRect r = fontMetrics().boundingRect(rect(), Qt::AlignLeft|Qt::AlignTop, text);
r.adjust(-2, -2, 1, 1);
p.translate(4, 4);
QColor bg = Qt::yellow;
bg.setAlpha(120);
p.setBrush(bg);
p.setPen(Qt::black);
p.drawRect(r);
p.drawText(rect(), Qt::AlignLeft|Qt::AlignTop, text);
#endif // DEBUG_SIZEHINTS
}
static QSpinBox *createSpinBox(int value, QWidget *parent, int max = 1000)
{
QSpinBox *result = new QSpinBox(parent);
result->setMinimum(-1);
result->setMaximum(max);
result->setValue(value);
return result;
}
void ColorDock::changeSizeHints()
{
QDialog dialog(this);
dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
dialog.setWindowTitle(color);
QVBoxLayout *topLayout = new QVBoxLayout(&dialog);
QGridLayout *inputLayout = new QGridLayout();
topLayout->addLayout(inputLayout);
inputLayout->addWidget(new QLabel(tr("Size Hint:"), &dialog), 0, 0);
inputLayout->addWidget(new QLabel(tr("Min Size Hint:"), &dialog), 1, 0);
inputLayout->addWidget(new QLabel(tr("Max Size:"), &dialog), 2, 0);
inputLayout->addWidget(new QLabel(tr("Dock Widget Max Size:"), &dialog), 3, 0);
QSpinBox *szHintW = createSpinBox(szHint.width(), &dialog);
inputLayout->addWidget(szHintW, 0, 1);
QSpinBox *szHintH = createSpinBox(szHint.height(), &dialog);
inputLayout->addWidget(szHintH, 0, 2);
QSpinBox *minSzHintW = createSpinBox(minSzHint.width(), &dialog);
inputLayout->addWidget(minSzHintW, 1, 1);
QSpinBox *minSzHintH = createSpinBox(minSzHint.height(), &dialog);
inputLayout->addWidget(minSzHintH, 1, 2);
QSize maxSz = maximumSize();
QSpinBox *maxSzW = createSpinBox(maxSz.width(), &dialog, QWIDGETSIZE_MAX);
inputLayout->addWidget(maxSzW, 2, 1);
QSpinBox *maxSzH = createSpinBox(maxSz.height(), &dialog, QWIDGETSIZE_MAX);
inputLayout->addWidget(maxSzH, 2, 2);
QSize dwMaxSz = parentWidget()->maximumSize();
QSpinBox *dwMaxSzW = createSpinBox(dwMaxSz.width(), &dialog, QWIDGETSIZE_MAX);
inputLayout->addWidget(dwMaxSzW, 3, 1);
QSpinBox *dwMaxSzH = createSpinBox(dwMaxSz.height(), &dialog, QWIDGETSIZE_MAX);
inputLayout->addWidget(dwMaxSzH, 3, 2);
inputLayout->setColumnStretch(1, 1);
inputLayout->setColumnStretch(2, 1);
topLayout->addStretch();
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
topLayout->addWidget(buttonBox);
if (dialog.exec() != QDialog::Accepted)
return;
szHint = QSize(szHintW->value(), szHintH->value());
minSzHint = QSize(minSzHintW->value(), minSzHintH->value());
maxSz = QSize(maxSzW->value(), maxSzH->value());
setMaximumSize(maxSz);
dwMaxSz = QSize(dwMaxSzW->value(), dwMaxSzH->value());
parentWidget()->setMaximumSize(dwMaxSz);
updateGeometry();
update();
}
void ColorDock::setCustomSizeHint(const QSize &size)
{
if (szHint != size) {
szHint = size;
updateGeometry();
}
}
ColorSwatch::ColorSwatch(const QString &colorName, QMainWindow *parent, Qt::WindowFlags flags)
: QDockWidget(parent, flags), mainWindow(parent)
{
setObjectName(colorName + QLatin1String(" Dock Widget"));
setWindowTitle(objectName() + QLatin1String(" [*]"));
ColorDock *swatch = new ColorDock(colorName, this);
swatch->setFrameStyle(QFrame::Box | QFrame::Sunken);
setWidget(swatch);
closableAction = new QAction(tr("Closable"), this);
closableAction->setCheckable(true);
connect(closableAction, &QAction::triggered, this, &ColorSwatch::changeClosable);
movableAction = new QAction(tr("Movable"), this);
movableAction->setCheckable(true);
connect(movableAction, &QAction::triggered, this, &ColorSwatch::changeMovable);
floatableAction = new QAction(tr("Floatable"), this);
floatableAction->setCheckable(true);
connect(floatableAction, &QAction::triggered, this, &ColorSwatch::changeFloatable);
verticalTitleBarAction = new QAction(tr("Vertical title bar"), this);
verticalTitleBarAction->setCheckable(true);
connect(verticalTitleBarAction, &QAction::triggered,
this, &ColorSwatch::changeVerticalTitleBar);
floatingAction = new QAction(tr("Floating"), this);
floatingAction->setCheckable(true);
connect(floatingAction, &QAction::triggered, this, &ColorSwatch::changeFloating);
allowedAreasActions = new QActionGroup(this);
allowedAreasActions->setExclusive(false);
allowLeftAction = new QAction(tr("Allow on Left"), this);
allowLeftAction->setCheckable(true);
connect(allowLeftAction, &QAction::triggered, this, &ColorSwatch::allowLeft);
allowRightAction = new QAction(tr("Allow on Right"), this);
allowRightAction->setCheckable(true);
connect(allowRightAction, &QAction::triggered, this, &ColorSwatch::allowRight);
allowTopAction = new QAction(tr("Allow on Top"), this);
allowTopAction->setCheckable(true);
connect(allowTopAction, &QAction::triggered, this, &ColorSwatch::allowTop);
allowBottomAction = new QAction(tr("Allow on Bottom"), this);
allowBottomAction->setCheckable(true);
connect(allowBottomAction, &QAction::triggered, this, &ColorSwatch::allowBottom);
allowedAreasActions->addAction(allowLeftAction);
allowedAreasActions->addAction(allowRightAction);
allowedAreasActions->addAction(allowTopAction);
allowedAreasActions->addAction(allowBottomAction);
areaActions = new QActionGroup(this);
areaActions->setExclusive(true);
leftAction = new QAction(tr("Place on Left") , this);
leftAction->setCheckable(true);
connect(leftAction, &QAction::triggered, this, &ColorSwatch::placeLeft);
rightAction = new QAction(tr("Place on Right") , this);
rightAction->setCheckable(true);
connect(rightAction, &QAction::triggered, this, &ColorSwatch::placeRight);
topAction = new QAction(tr("Place on Top") , this);
topAction->setCheckable(true);
connect(topAction, &QAction::triggered, this, &ColorSwatch::placeTop);
bottomAction = new QAction(tr("Place on Bottom") , this);
bottomAction->setCheckable(true);
connect(bottomAction, &QAction::triggered, this, &ColorSwatch::placeBottom);
areaActions->addAction(leftAction);
areaActions->addAction(rightAction);
areaActions->addAction(topAction);
areaActions->addAction(bottomAction);
connect(movableAction, &QAction::triggered, areaActions, &QActionGroup::setEnabled);
connect(movableAction, &QAction::triggered, allowedAreasActions, &QActionGroup::setEnabled);
connect(floatableAction, &QAction::triggered, floatingAction, &QAction::setEnabled);
connect(floatingAction, &QAction::triggered, floatableAction, &QAction::setDisabled);
connect(movableAction, &QAction::triggered, floatableAction, &QAction::setEnabled);
tabMenu = new QMenu(this);
tabMenu->setTitle(tr("Tab into"));
connect(tabMenu, &QMenu::triggered, this, &ColorSwatch::tabInto);
splitHMenu = new QMenu(this);
splitHMenu->setTitle(tr("Split horizontally into"));
connect(splitHMenu, &QMenu::triggered, this, &ColorSwatch::splitInto);
splitVMenu = new QMenu(this);
splitVMenu->setTitle(tr("Split vertically into"));
connect(splitVMenu, &QMenu::triggered, this, &ColorSwatch::splitInto);
QAction *windowModifiedAction = new QAction(tr("Modified"), this);
windowModifiedAction->setCheckable(true);
windowModifiedAction->setChecked(false);
connect(windowModifiedAction, &QAction::toggled, this, &QWidget::setWindowModified);
menu = new QMenu(colorName, this);
menu->addAction(toggleViewAction());
menu->addAction(tr("Raise"), this, &QWidget::raise);
menu->addAction(tr("Change Size Hints..."), swatch, &ColorDock::changeSizeHints);
menu->addSeparator();
menu->addAction(closableAction);
menu->addAction(movableAction);
menu->addAction(floatableAction);
menu->addAction(floatingAction);
menu->addAction(verticalTitleBarAction);
menu->addSeparator();
menu->addActions(allowedAreasActions->actions());
menu->addSeparator();
menu->addActions(areaActions->actions());
menu->addSeparator();
menu->addMenu(splitHMenu);
menu->addMenu(splitVMenu);
menu->addMenu(tabMenu);
menu->addSeparator();
menu->addAction(windowModifiedAction);
connect(menu, &QMenu::aboutToShow, this, &ColorSwatch::updateContextMenu);
if (colorName == QLatin1String("Black")) {
leftAction->setShortcut(Qt::CTRL | Qt::Key_W);
rightAction->setShortcut(Qt::CTRL | Qt::Key_E);
toggleViewAction()->setShortcut(Qt::CTRL | Qt::Key_R);
}
}
void ColorSwatch::updateContextMenu()
{
const Qt::DockWidgetArea area = mainWindow->dockWidgetArea(this);
const Qt::DockWidgetAreas areas = allowedAreas();
closableAction->setChecked(features() & QDockWidget::DockWidgetClosable);
if (windowType() == Qt::Drawer) {
floatableAction->setEnabled(false);
floatingAction->setEnabled(false);
movableAction->setEnabled(false);
verticalTitleBarAction->setChecked(false);
} else {
floatableAction->setChecked(features() & QDockWidget::DockWidgetFloatable);
floatingAction->setChecked(isWindow());
// done after floating, to get 'floatable' correctly initialized
movableAction->setChecked(features() & QDockWidget::DockWidgetMovable);
verticalTitleBarAction
->setChecked(features() & QDockWidget::DockWidgetVerticalTitleBar);
}
allowLeftAction->setChecked(isAreaAllowed(Qt::LeftDockWidgetArea));
allowRightAction->setChecked(isAreaAllowed(Qt::RightDockWidgetArea));
allowTopAction->setChecked(isAreaAllowed(Qt::TopDockWidgetArea));
allowBottomAction->setChecked(isAreaAllowed(Qt::BottomDockWidgetArea));
if (allowedAreasActions->isEnabled()) {
allowLeftAction->setEnabled(area != Qt::LeftDockWidgetArea);
allowRightAction->setEnabled(area != Qt::RightDockWidgetArea);
allowTopAction->setEnabled(area != Qt::TopDockWidgetArea);
allowBottomAction->setEnabled(area != Qt::BottomDockWidgetArea);
}
{
const QSignalBlocker blocker(leftAction);
leftAction->setChecked(area == Qt::LeftDockWidgetArea);
}
{
const QSignalBlocker blocker(rightAction);
rightAction->setChecked(area == Qt::RightDockWidgetArea);
}
{
const QSignalBlocker blocker(topAction);
topAction->setChecked(area == Qt::TopDockWidgetArea);
}
{
const QSignalBlocker blocker(bottomAction);
bottomAction->setChecked(area == Qt::BottomDockWidgetArea);
}
if (areaActions->isEnabled()) {
leftAction->setEnabled(areas & Qt::LeftDockWidgetArea);
rightAction->setEnabled(areas & Qt::RightDockWidgetArea);
topAction->setEnabled(areas & Qt::TopDockWidgetArea);
bottomAction->setEnabled(areas & Qt::BottomDockWidgetArea);
}
tabMenu->clear();
splitHMenu->clear();
splitVMenu->clear();
const QList<ColorSwatch *> dockList = mainWindow->findChildren<ColorSwatch*>();
for (const ColorSwatch *dock : dockList) {
tabMenu->addAction(dock->objectName());
splitHMenu->addAction(dock->objectName());
splitVMenu->addAction(dock->objectName());
}
}
static ColorSwatch *findByName(const QMainWindow *mainWindow, const QString &name)
{
const QList<ColorSwatch *> dockList = mainWindow->findChildren<ColorSwatch*>();
for (ColorSwatch *dock : dockList) {
if (name == dock->objectName())
return dock;
}
return nullptr;
}
void ColorSwatch::splitInto(QAction *action)
{
ColorSwatch *target = findByName(mainWindow, action->text());
if (!target)
return;
const Qt::Orientation o = action->parent() == splitHMenu
? Qt::Horizontal : Qt::Vertical;
mainWindow->splitDockWidget(target, this, o);
}
void ColorSwatch::tabInto(QAction *action)
{
if (ColorSwatch *target = findByName(mainWindow, action->text()))
mainWindow->tabifyDockWidget(target, this);
}
#ifndef QT_NO_CONTEXTMENU
void ColorSwatch::contextMenuEvent(QContextMenuEvent *event)
{
event->accept();
menu->popup(event->globalPos());
}
#endif // QT_NO_CONTEXTMENU
void ColorSwatch::resizeEvent(QResizeEvent *e)
{
if (BlueTitleBar *btb = qobject_cast<BlueTitleBar*>(titleBarWidget()))
btb->updateMask();
QDockWidget::resizeEvent(e);
}
void ColorSwatch::allow(Qt::DockWidgetArea area, bool a)
{
Qt::DockWidgetAreas areas = allowedAreas();
areas = a ? areas | area : areas & ~area;
setAllowedAreas(areas);
if (areaActions->isEnabled()) {
leftAction->setEnabled(areas & Qt::LeftDockWidgetArea);
rightAction->setEnabled(areas & Qt::RightDockWidgetArea);
topAction->setEnabled(areas & Qt::TopDockWidgetArea);
bottomAction->setEnabled(areas & Qt::BottomDockWidgetArea);
}
}
void ColorSwatch::place(Qt::DockWidgetArea area, bool p)
{
if (!p)
return;
mainWindow->addDockWidget(area, this);
if (allowedAreasActions->isEnabled()) {
allowLeftAction->setEnabled(area != Qt::LeftDockWidgetArea);
allowRightAction->setEnabled(area != Qt::RightDockWidgetArea);
allowTopAction->setEnabled(area != Qt::TopDockWidgetArea);
allowBottomAction->setEnabled(area != Qt::BottomDockWidgetArea);
}
}
void ColorSwatch::setCustomSizeHint(const QSize &size)
{
if (ColorDock *dock = qobject_cast<ColorDock*>(widget()))
dock->setCustomSizeHint(size);
}
void ColorSwatch::changeClosable(bool on)
{ setFeatures(on ? features() | DockWidgetClosable : features() & ~DockWidgetClosable); }
void ColorSwatch::changeMovable(bool on)
{ setFeatures(on ? features() | DockWidgetMovable : features() & ~DockWidgetMovable); }
void ColorSwatch::changeFloatable(bool on)
{ setFeatures(on ? features() | DockWidgetFloatable : features() & ~DockWidgetFloatable); }
void ColorSwatch::changeFloating(bool floating)
{ setFloating(floating); }
void ColorSwatch::allowLeft(bool a)
{ allow(Qt::LeftDockWidgetArea, a); }
void ColorSwatch::allowRight(bool a)
{ allow(Qt::RightDockWidgetArea, a); }
void ColorSwatch::allowTop(bool a)
{ allow(Qt::TopDockWidgetArea, a); }
void ColorSwatch::allowBottom(bool a)
{ allow(Qt::BottomDockWidgetArea, a); }
void ColorSwatch::placeLeft(bool p)
{ place(Qt::LeftDockWidgetArea, p); }
void ColorSwatch::placeRight(bool p)
{ place(Qt::RightDockWidgetArea, p); }
void ColorSwatch::placeTop(bool p)
{ place(Qt::TopDockWidgetArea, p); }
void ColorSwatch::placeBottom(bool p)
{ place(Qt::BottomDockWidgetArea, p); }
void ColorSwatch::changeVerticalTitleBar(bool on)
{
setFeatures(on ? features() | DockWidgetVerticalTitleBar
: features() & ~DockWidgetVerticalTitleBar);
}
QSize BlueTitleBar::minimumSizeHint() const
{
QDockWidget *dw = qobject_cast<QDockWidget*>(parentWidget());
Q_ASSERT(dw);
QSize result(leftPm.width() + rightPm.width(), centerPm.height());
if (dw->features() & QDockWidget::DockWidgetVerticalTitleBar)
result.transpose();
return result;
}
BlueTitleBar::BlueTitleBar(QWidget *parent)
: QWidget(parent)
, leftPm(QPixmap(":/res/titlebarLeft.png"))
, centerPm(QPixmap(":/res/titlebarCenter.png"))
, rightPm(QPixmap(":/res/titlebarRight.png"))
{
}
void BlueTitleBar::paintEvent(QPaintEvent*)
{
QPainter painter(this);
QRect rect = this->rect();
QDockWidget *dw = qobject_cast<QDockWidget*>(parentWidget());
Q_ASSERT(dw);
if (dw->features() & QDockWidget::DockWidgetVerticalTitleBar) {
QSize s = rect.size();
s.transpose();
rect.setSize(s);
painter.translate(rect.left(), rect.top() + rect.width());
painter.rotate(-90);
painter.translate(-rect.left(), -rect.top());
}
painter.drawPixmap(rect.topLeft(), leftPm);
painter.drawPixmap(rect.topRight() - QPoint(rightPm.width() - 1, 0), rightPm);
QBrush brush(centerPm);
painter.fillRect(rect.left() + leftPm.width(), rect.top(),
rect.width() - leftPm.width() - rightPm.width(),
centerPm.height(), centerPm);
}
void BlueTitleBar::mouseReleaseEvent(QMouseEvent *event)
{
QPoint pos = event->position().toPoint();
QRect rect = this->rect();
QDockWidget *dw = qobject_cast<QDockWidget*>(parentWidget());
Q_ASSERT(dw);
if (dw->features() & QDockWidget::DockWidgetVerticalTitleBar) {
QPoint p = pos;
pos.setX(rect.left() + rect.bottom() - p.y());
pos.setY(rect.top() + p.x() - rect.left());
QSize s = rect.size();
s.transpose();
rect.setSize(s);
}
const int buttonRight = 7;
const int buttonWidth = 20;
int right = rect.right() - pos.x();
int button = (right - buttonRight)/buttonWidth;
switch (button) {
case 0:
event->accept();
dw->close();
break;
case 1:
event->accept();
dw->setFloating(!dw->isFloating());
break;
case 2: {
event->accept();
QDockWidget::DockWidgetFeatures features = dw->features();
if (features & QDockWidget::DockWidgetVerticalTitleBar)
features &= ~QDockWidget::DockWidgetVerticalTitleBar;
else
features |= QDockWidget::DockWidgetVerticalTitleBar;
dw->setFeatures(features);
break;
}
default:
event->ignore();
break;
}
}
void BlueTitleBar::updateMask()
{
QDockWidget *dw = qobject_cast<QDockWidget*>(parent());
Q_ASSERT(dw);
QRect rect = dw->rect();
QBitmap bitmap(dw->size());
{
QPainter painter(&bitmap);
// initialize to transparent
painter.fillRect(rect, Qt::color0);
QRect contents = rect;
contents.setTopLeft(geometry().bottomLeft());
contents.setRight(geometry().right());
contents.setBottom(contents.bottom()-y());
painter.fillRect(contents, Qt::color1);
// let's paint the titlebar
QRect titleRect = this->geometry();
if (dw->features() & QDockWidget::DockWidgetVerticalTitleBar) {
QSize s = rect.size();
s.transpose();
rect.setSize(s);
QSize s2 = size();
s2.transpose();
titleRect.setSize(s2);
painter.translate(rect.left(), rect.top() + rect.width());
painter.rotate(-90);
painter.translate(-rect.left(), -rect.top());
}
contents.setTopLeft(titleRect.bottomLeft());
contents.setRight(titleRect.right());
contents.setBottom(rect.bottom()-y());
QRect rect = titleRect;
painter.drawPixmap(rect.topLeft(), leftPm.mask());
painter.fillRect(rect.left() + leftPm.width(), rect.top(),
rect.width() - leftPm.width() - rightPm.width(),
centerPm.height(), Qt::color1);
painter.drawPixmap(rect.topRight() - QPoint(rightPm.width() - 1, 0), rightPm.mask());
painter.fillRect(contents, Qt::color1);
}
dw->setMask(bitmap);
}
#include "colorswatch.moc"

View File

@ -0,0 +1,102 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef COLORSWATCH_H
#define COLORSWATCH_H
#include <QDockWidget>
QT_FORWARD_DECLARE_CLASS(QAction)
QT_FORWARD_DECLARE_CLASS(QActionGroup)
QT_FORWARD_DECLARE_CLASS(QMenu)
class ColorSwatch : public QDockWidget
{
Q_OBJECT
public:
explicit ColorSwatch(const QString &colorName, QMainWindow *parent = nullptr, Qt::WindowFlags flags = { });
void setCustomSizeHint(const QSize &size);
QMenu *colorSwatchMenu() const { return menu; }
protected:
#ifndef QT_NO_CONTEXTMENU
void contextMenuEvent(QContextMenuEvent *event) override;
#endif // QT_NO_CONTEXTMENU
void resizeEvent(QResizeEvent *e) override;
private slots:
void changeClosable(bool on);
void changeMovable(bool on);
void changeFloatable(bool on);
void changeFloating(bool on);
void changeVerticalTitleBar(bool on);
void updateContextMenu();
void allowLeft(bool a);
void allowRight(bool a);
void allowTop(bool a);
void allowBottom(bool a);
void placeLeft(bool p);
void placeRight(bool p);
void placeTop(bool p);
void placeBottom(bool p);
void splitInto(QAction *action);
void tabInto(QAction *action);
private:
void allow(Qt::DockWidgetArea area, bool allow);
void place(Qt::DockWidgetArea area, bool place);
QAction *closableAction;
QAction *movableAction;
QAction *floatableAction;
QAction *floatingAction;
QAction *verticalTitleBarAction;
QActionGroup *allowedAreasActions;
QAction *allowLeftAction;
QAction *allowRightAction;
QAction *allowTopAction;
QAction *allowBottomAction;
QActionGroup *areaActions;
QAction *leftAction;
QAction *rightAction;
QAction *topAction;
QAction *bottomAction;
QMenu *tabMenu;
QMenu *splitHMenu;
QMenu *splitVMenu;
QMenu *menu;
QMainWindow *mainWindow;
};
class BlueTitleBar : public QWidget
{
Q_OBJECT
public:
explicit BlueTitleBar(QWidget *parent = nullptr);
QSize sizeHint() const override { return minimumSizeHint(); }
QSize minimumSizeHint() const override;
protected:
void paintEvent(QPaintEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
public slots:
void updateMask();
private:
const QPixmap leftPm;
const QPixmap centerPm;
const QPixmap rightPm;
};
#endif // COLORSWATCH_H

View File

@ -0,0 +1,147 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "mainwindow.h"
#include <QApplication>
#include <QPainterPath>
#include <QPainter>
#include <QMap>
#include <QDebug>
void render_qt_text(QPainter *painter, int w, int h, const QColor &color)
{
QPainterPath path;
path.moveTo(-0.083695, 0.283849);
path.cubicTo(-0.049581, 0.349613, -0.012720, 0.397969, 0.026886, 0.428917);
path.cubicTo(0.066493, 0.459865, 0.111593, 0.477595, 0.162186, 0.482108);
path.lineTo(0.162186, 0.500000);
path.cubicTo(0.115929, 0.498066, 0.066565, 0.487669, 0.014094, 0.468810);
path.cubicTo(-0.038378, 0.449952, -0.088103, 0.423839, -0.135082, 0.390474);
path.cubicTo(-0.182061, 0.357108, -0.222608, 0.321567, -0.256722, 0.283849);
path.cubicTo(-0.304712, 0.262250, -0.342874, 0.239362, -0.371206, 0.215184);
path.cubicTo(-0.411969, 0.179078, -0.443625, 0.134671, -0.466175, 0.081963);
path.cubicTo(-0.488725, 0.029255, -0.500000, -0.033043, -0.500000, -0.104932);
path.cubicTo(-0.500000, -0.218407, -0.467042, -0.312621, -0.401127, -0.387573);
path.cubicTo(-0.335212, -0.462524, -0.255421, -0.500000, -0.161752, -0.500000);
path.cubicTo(-0.072998, -0.500000, 0.003903, -0.462444, 0.068951, -0.387331);
path.cubicTo(0.133998, -0.312218, 0.166522, -0.217440, 0.166522, -0.102998);
path.cubicTo(0.166522, -0.010155, 0.143394, 0.071325, 0.097138, 0.141441);
path.cubicTo(0.050882, 0.211557, -0.009396, 0.259026, -0.083695, 0.283849);
path.moveTo(-0.167823, -0.456963);
path.cubicTo(-0.228823, -0.456963, -0.277826, -0.432624, -0.314831, -0.383946);
path.cubicTo(-0.361665, -0.323340, -0.385082, -0.230335, -0.385082, -0.104932);
path.cubicTo(-0.385082, 0.017569, -0.361376, 0.112025, -0.313964, 0.178433);
path.cubicTo(-0.277248, 0.229368, -0.228534, 0.254836, -0.167823, 0.254836);
path.cubicTo(-0.105088, 0.254836, -0.054496, 0.229368, -0.016045, 0.178433);
path.cubicTo(0.029055, 0.117827, 0.051605, 0.028691, 0.051605, -0.088975);
path.cubicTo(0.051605, -0.179562, 0.039318, -0.255803, 0.014744, -0.317698);
path.cubicTo(-0.004337, -0.365409, -0.029705, -0.400548, -0.061362, -0.423114);
path.cubicTo(-0.093018, -0.445680, -0.128505, -0.456963, -0.167823, -0.456963);
path.moveTo(0.379011, -0.404739);
path.lineTo(0.379011, -0.236460);
path.lineTo(0.486123, -0.236460);
path.lineTo(0.486123, -0.197292);
path.lineTo(0.379011, -0.197292);
path.lineTo(0.379011, 0.134913);
path.cubicTo(0.379011, 0.168117, 0.383276, 0.190442, 0.391804, 0.201886);
path.cubicTo(0.400332, 0.213330, 0.411246, 0.219052, 0.424545, 0.219052);
path.cubicTo(0.435531, 0.219052, 0.446227, 0.215264, 0.456635, 0.207689);
path.cubicTo(0.467042, 0.200113, 0.474993, 0.188910, 0.480486, 0.174081);
path.lineTo(0.500000, 0.174081);
path.cubicTo(0.488436, 0.210509, 0.471957, 0.237911, 0.450564, 0.256286);
path.cubicTo(0.429170, 0.274662, 0.407054, 0.283849, 0.384215, 0.283849);
path.cubicTo(0.368893, 0.283849, 0.353859, 0.279094, 0.339115, 0.269584);
path.cubicTo(0.324371, 0.260074, 0.313530, 0.246534, 0.306592, 0.228965);
path.cubicTo(0.299653, 0.211396, 0.296184, 0.184075, 0.296184, 0.147002);
path.lineTo(0.296184, -0.197292);
path.lineTo(0.223330, -0.197292);
path.lineTo(0.223330, -0.215667);
path.cubicTo(0.241833, -0.224049, 0.260697, -0.237992, 0.279922, -0.257495);
path.cubicTo(0.299147, -0.276999, 0.316276, -0.300129, 0.331310, -0.326886);
path.cubicTo(0.338826, -0.341070, 0.349523, -0.367021, 0.363400, -0.404739);
path.lineTo(0.379011, -0.404739);
path.moveTo(-0.535993, 0.275629);
painter->translate(w / 2, h / 2);
double scale = qMin(w, h) * 8 / 10.0;
painter->scale(scale, scale);
painter->setRenderHint(QPainter::Antialiasing);
painter->save();
painter->translate(.1, .1);
painter->fillPath(path, QColor(0, 0, 0, 63));
painter->restore();
painter->setBrush(color);
painter->setPen(QPen(Qt::black, 0.02, Qt::SolidLine, Qt::FlatCap, Qt::RoundJoin));
painter->drawPath(path);
}
static void usage()
{
qWarning() << "Usage: mainwindow [-SizeHint<color> <width>x<height>] ...";
exit(1);
}
enum ParseCommandLineArgumentsResult {
CommandLineArgumentsOk,
CommandLineArgumentsError,
HelpRequested
};
static ParseCommandLineArgumentsResult
parseCustomSizeHints(const QStringList &arguments, MainWindow::CustomSizeHintMap *result)
{
result->clear();
const auto argumentCount = arguments.size();
for (int i = 1; i < argumentCount; ++i) {
const QString &arg = arguments.at(i);
if (arg.startsWith(QLatin1String("-SizeHint"))) {
const QString name = arg.mid(9);
if (name.isEmpty())
return CommandLineArgumentsError;
if (++i == argumentCount)
return CommandLineArgumentsError;
const QStringView sizeStr{ arguments.at(i) };
const auto idx = sizeStr.indexOf(QLatin1Char('x'));
if (idx == -1)
return CommandLineArgumentsError;
bool ok;
const int w = sizeStr.left(idx).toInt(&ok);
if (!ok)
return CommandLineArgumentsError;
const int h = sizeStr.mid(idx + 1).toInt(&ok);
if (!ok)
return CommandLineArgumentsError;
result->insert(name, QSize(w, h));
} else if (arg == QLatin1String("-h") || arg == QLatin1String("--help")) {
return HelpRequested;
} else {
return CommandLineArgumentsError;
}
}
return CommandLineArgumentsOk;
}
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MainWindow::CustomSizeHintMap customSizeHints;
switch (parseCustomSizeHints(QCoreApplication::arguments(), &customSizeHints)) {
case CommandLineArgumentsOk:
break;
case CommandLineArgumentsError:
usage();
return -1;
case HelpRequested:
usage();
return 0;
}
MainWindow mainWin(customSizeHints);
mainWin.resize(800, 600);
mainWin.show();
return app.exec();
}

View File

@ -0,0 +1,444 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "mainwindow.h"
#include "colorswatch.h"
#include "toolbar.h"
#include <QActionGroup>
#include <QLayout>
#include <QMenu>
#include <QMenuBar>
#include <QStatusBar>
#include <QTextEdit>
#include <QFile>
#include <QDataStream>
#include <QFileDialog>
#include <QDialogButtonBox>
#include <QMessageBox>
#include <QApplication>
#include <QPainter>
#include <QMouseEvent>
#include <QLineEdit>
#include <QComboBox>
#include <QLabel>
#include <QPushButton>
#include <QTextEdit>
#include <QDebug>
static const char message[] =
"<p><b>Qt Main Window Example</b></p>"
"<p>This is a demonstration of the QMainWindow, QToolBar and "
"QDockWidget classes.</p>"
"<p>The tool bar and dock widgets can be dragged around and rearranged "
"using the mouse or via the menu.</p>"
"<p>Each dock widget contains a colored frame and a context "
"(right-click) menu.</p>"
#ifdef Q_OS_MAC
"<p>On OS X, the \"Black\" dock widget has been created as a "
"<em>Drawer</em>, which is a special kind of QDockWidget.</p>"
#endif
;
Q_DECLARE_METATYPE(QDockWidget::DockWidgetFeatures)
MainWindow::MainWindow(const CustomSizeHintMap &customSizeHints,
QWidget *parent, Qt::WindowFlags flags)
: QMainWindow(parent, flags)
{
Q_UNUSED(message);
setObjectName("MainWindow");
setWindowTitle("Qt Main Window Example");
QTextEdit *center = new QTextEdit(this);
center->setReadOnly(true);
center->setMinimumSize(400, 205);
setCentralWidget(center);
setupToolBar();
setupMenuBar();
setupDockWidgets(customSizeHints);
statusBar()->showMessage(tr("Status Bar"));
}
void MainWindow::actionTriggered(QAction *action)
{
qDebug("action '%s' triggered", action->text().toLocal8Bit().data());
}
void MainWindow::setupToolBar()
{
#ifdef Q_OS_MACOS
setUnifiedTitleAndToolBarOnMac(true);
#endif
for (int i = 0; i < 3; ++i) {
ToolBar *tb = new ToolBar(QString::fromLatin1("Tool Bar %1").arg(i + 1), this);
toolBars.append(tb);
addToolBar(tb);
}
}
void MainWindow::setupMenuBar()
{
QMenu *menu = menuBar()->addMenu(tr("&File"));
menu->addAction(tr("Save layout..."), this, &MainWindow::saveLayout);
menu->addAction(tr("Load layout..."), this, &MainWindow::loadLayout);
menu->addAction(tr("Switch layout direction"),this, &MainWindow::switchLayoutDirection);
menu->addSeparator();
menu->addAction(tr("&Quit"), qApp, &QCoreApplication::quit);
mainWindowMenu = menuBar()->addMenu(tr("Main window"));
QAction *action = mainWindowMenu->addAction(tr("Animated docks"));
action->setCheckable(true);
action->setChecked(dockOptions() & AnimatedDocks);
connect(action, &QAction::toggled, this, &MainWindow::setDockOptions);
action = mainWindowMenu->addAction(tr("Allow nested docks"));
action->setCheckable(true);
action->setChecked(dockOptions() & AllowNestedDocks);
connect(action, &QAction::toggled, this, &MainWindow::setDockOptions);
action = mainWindowMenu->addAction(tr("Allow tabbed docks"));
action->setCheckable(true);
action->setChecked(dockOptions() & AllowTabbedDocks);
connect(action, &QAction::toggled, this, &MainWindow::setDockOptions);
action = mainWindowMenu->addAction(tr("Force tabbed docks"));
action->setCheckable(true);
action->setChecked(dockOptions() & ForceTabbedDocks);
connect(action, &QAction::toggled, this, &MainWindow::setDockOptions);
action = mainWindowMenu->addAction(tr("Vertical tabs"));
action->setCheckable(true);
action->setChecked(dockOptions() & VerticalTabs);
connect(action, &QAction::toggled, this, &MainWindow::setDockOptions);
action = mainWindowMenu->addAction(tr("Grouped dragging"));
action->setCheckable(true);
action->setChecked(dockOptions() & GroupedDragging);
connect(action, &QAction::toggled, this, &MainWindow::setDockOptions);
QMenu *toolBarMenu = menuBar()->addMenu(tr("Tool bars"));
for (int i = 0; i < toolBars.count(); ++i)
toolBarMenu->addMenu(toolBars.at(i)->toolbarMenu());
#ifdef Q_OS_MACOS
toolBarMenu->addSeparator();
action = toolBarMenu->addAction(tr("Unified"));
action->setCheckable(true);
action->setChecked(unifiedTitleAndToolBarOnMac());
connect(action, &QAction::toggled, this, &QMainWindow::setUnifiedTitleAndToolBarOnMac);
#endif
dockWidgetMenu = menuBar()->addMenu(tr("&Dock Widgets"));
QMenu *aboutMenu = menuBar()->addMenu(tr("About"));
QAction *aboutAct = aboutMenu->addAction(tr("&About"), this, &MainWindow::about);
aboutAct->setStatusTip(tr("Show the application's About box"));
QAction *aboutQtAct = aboutMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt);
aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
}
void MainWindow::setDockOptions()
{
DockOptions opts;
QList<QAction*> actions = mainWindowMenu->actions();
if (actions.at(0)->isChecked())
opts |= AnimatedDocks;
if (actions.at(1)->isChecked())
opts |= AllowNestedDocks;
if (actions.at(2)->isChecked())
opts |= AllowTabbedDocks;
if (actions.at(3)->isChecked())
opts |= ForceTabbedDocks;
if (actions.at(4)->isChecked())
opts |= VerticalTabs;
if (actions.at(5)->isChecked())
opts |= GroupedDragging;
QMainWindow::setDockOptions(opts);
}
void MainWindow::saveLayout()
{
QString fileName
= QFileDialog::getSaveFileName(this, tr("Save layout"));
if (fileName.isEmpty())
return;
QFile file(fileName);
if (!file.open(QFile::WriteOnly)) {
QString msg = tr("Failed to open %1\n%2")
.arg(QDir::toNativeSeparators(fileName), file.errorString());
QMessageBox::warning(this, tr("Error"), msg);
return;
}
QByteArray geo_data = saveGeometry();
QByteArray layout_data = saveState();
bool ok = file.putChar((uchar)geo_data.size());
if (ok)
ok = file.write(geo_data) == geo_data.size();
if (ok)
ok = file.write(layout_data) == layout_data.size();
if (!ok) {
QString msg = tr("Error writing to %1\n%2")
.arg(QDir::toNativeSeparators(fileName), file.errorString());
QMessageBox::warning(this, tr("Error"), msg);
return;
}
}
void MainWindow::loadLayout()
{
QString fileName
= QFileDialog::getOpenFileName(this, tr("Load layout"));
if (fileName.isEmpty())
return;
QFile file(fileName);
if (!file.open(QFile::ReadOnly)) {
QString msg = tr("Failed to open %1\n%2")
.arg(QDir::toNativeSeparators(fileName), file.errorString());
QMessageBox::warning(this, tr("Error"), msg);
return;
}
uchar geo_size;
QByteArray geo_data;
QByteArray layout_data;
bool ok = file.getChar((char*)&geo_size);
if (ok) {
geo_data = file.read(geo_size);
ok = geo_data.size() == geo_size;
}
if (ok) {
layout_data = file.readAll();
ok = layout_data.size() > 0;
}
if (ok)
ok = restoreGeometry(geo_data);
if (ok)
ok = restoreState(layout_data);
if (!ok) {
QString msg = tr("Error reading %1").arg(QDir::toNativeSeparators(fileName));
QMessageBox::warning(this, tr("Error"), msg);
return;
}
}
static QAction *addCornerAction(const QString &text, QMainWindow *mw, QMenu *menu, QActionGroup *group,
Qt::Corner c, Qt::DockWidgetArea a)
{
QAction *result = menu->addAction(text, mw, [=]() { mw->setCorner(c, a); });
result->setCheckable(true);
group->addAction(result);
return result;
}
void MainWindow::setupDockWidgets(const CustomSizeHintMap &customSizeHints)
{
qRegisterMetaType<QDockWidget::DockWidgetFeatures>();
QMenu *cornerMenu = dockWidgetMenu->addMenu(tr("Top left corner"));
QActionGroup *group = new QActionGroup(this);
group->setExclusive(true);
QAction *cornerAction = addCornerAction(tr("Top dock area"), this, cornerMenu, group, Qt::TopLeftCorner, Qt::TopDockWidgetArea);
cornerAction->setChecked(true);
addCornerAction(tr("Left dock area"), this, cornerMenu, group, Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
cornerMenu = dockWidgetMenu->addMenu(tr("Top right corner"));
group = new QActionGroup(this);
group->setExclusive(true);
cornerAction = addCornerAction(tr("Top dock area"), this, cornerMenu, group, Qt::TopRightCorner, Qt::TopDockWidgetArea);
cornerAction->setChecked(true);
addCornerAction(tr("Right dock area"), this, cornerMenu, group, Qt::TopRightCorner, Qt::RightDockWidgetArea);
cornerMenu = dockWidgetMenu->addMenu(tr("Bottom left corner"));
group = new QActionGroup(this);
group->setExclusive(true);
cornerAction = addCornerAction(tr("Bottom dock area"), this, cornerMenu, group, Qt::BottomLeftCorner, Qt::BottomDockWidgetArea);
cornerAction->setChecked(true);
addCornerAction(tr("Left dock area"), this, cornerMenu, group, Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
cornerMenu = dockWidgetMenu->addMenu(tr("Bottom right corner"));
group = new QActionGroup(this);
group->setExclusive(true);
cornerAction = addCornerAction(tr("Bottom dock area"), this, cornerMenu, group, Qt::BottomRightCorner, Qt::BottomDockWidgetArea);
cornerAction->setChecked(true);
addCornerAction(tr("Right dock area"), this, cornerMenu, group, Qt::BottomRightCorner, Qt::RightDockWidgetArea);
dockWidgetMenu->addSeparator();
static const struct Set {
const char * name;
uint flags;
Qt::DockWidgetArea area;
} sets [] = {
#ifndef Q_OS_MAC
{ "Black", 0, Qt::LeftDockWidgetArea },
#else
{ "Black", Qt::Drawer, Qt::LeftDockWidgetArea },
#endif
{ "White", 0, Qt::RightDockWidgetArea },
{ "Red", 0, Qt::TopDockWidgetArea },
{ "Green", 0, Qt::TopDockWidgetArea },
{ "Blue", 0, Qt::BottomDockWidgetArea },
{ "Yellow", 0, Qt::BottomDockWidgetArea }
};
const int setCount = sizeof(sets) / sizeof(Set);
const QIcon qtIcon(QPixmap(":/res/qt.png"));
for (int i = 0; i < setCount; ++i) {
ColorSwatch *swatch = new ColorSwatch(tr(sets[i].name), this, Qt::WindowFlags(sets[i].flags));
if (i % 2)
swatch->setWindowIcon(qtIcon);
if (qstrcmp(sets[i].name, "Blue") == 0) {
BlueTitleBar *titlebar = new BlueTitleBar(swatch);
swatch->setTitleBarWidget(titlebar);
connect(swatch, &QDockWidget::topLevelChanged, titlebar, &BlueTitleBar::updateMask);
connect(swatch, &QDockWidget::featuresChanged, titlebar, &BlueTitleBar::updateMask, Qt::QueuedConnection);
}
QString name = QString::fromLatin1(sets[i].name);
if (customSizeHints.contains(name))
swatch->setCustomSizeHint(customSizeHints.value(name));
addDockWidget(sets[i].area, swatch);
dockWidgetMenu->addMenu(swatch->colorSwatchMenu());
}
destroyDockWidgetMenu = new QMenu(tr("Destroy dock widget"), this);
destroyDockWidgetMenu->setEnabled(false);
connect(destroyDockWidgetMenu, &QMenu::triggered, this, &MainWindow::destroyDockWidget);
dockWidgetMenu->addSeparator();
dockWidgetMenu->addAction(tr("Add dock widget..."), this, &MainWindow::createDockWidget);
dockWidgetMenu->addMenu(destroyDockWidgetMenu);
}
void MainWindow::switchLayoutDirection()
{
if (layoutDirection() == Qt::LeftToRight)
QApplication::setLayoutDirection(Qt::RightToLeft);
else
QApplication::setLayoutDirection(Qt::LeftToRight);
}
class CreateDockWidgetDialog : public QDialog
{
public:
explicit CreateDockWidgetDialog(QWidget *parent = nullptr);
QString enteredObjectName() const { return m_objectName->text(); }
Qt::DockWidgetArea location() const;
private:
QLineEdit *m_objectName;
QComboBox *m_location;
};
CreateDockWidgetDialog::CreateDockWidgetDialog(QWidget *parent)
: QDialog(parent)
, m_objectName(new QLineEdit(this))
, m_location(new QComboBox(this))
{
setWindowTitle(tr("Add Dock Widget"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
QGridLayout *layout = new QGridLayout(this);
layout->addWidget(new QLabel(tr("Object name:")), 0, 0);
layout->addWidget(m_objectName, 0, 1);
layout->addWidget(new QLabel(tr("Location:")), 1, 0);
m_location->setEditable(false);
m_location->addItem(tr("Top"));
m_location->addItem(tr("Left"));
m_location->addItem(tr("Right"));
m_location->addItem(tr("Bottom"));
m_location->addItem(tr("Restore"));
layout->addWidget(m_location, 1, 1);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
layout->addWidget(buttonBox, 2, 0, 1, 2);
}
Qt::DockWidgetArea CreateDockWidgetDialog::location() const
{
switch (m_location->currentIndex()) {
case 0: return Qt::TopDockWidgetArea;
case 1: return Qt::LeftDockWidgetArea;
case 2: return Qt::RightDockWidgetArea;
case 3: return Qt::BottomDockWidgetArea;
default:
break;
}
return Qt::NoDockWidgetArea;
}
void MainWindow::createDockWidget()
{
CreateDockWidgetDialog dialog(this);
if (dialog.exec() == QDialog::Rejected)
return;
QDockWidget *dw = new QDockWidget;
const QString name = dialog.enteredObjectName();
dw->setObjectName(name);
dw->setWindowTitle(name);
dw->setWidget(new QTextEdit);
Qt::DockWidgetArea area = dialog.location();
switch (area) {
case Qt::LeftDockWidgetArea:
case Qt::RightDockWidgetArea:
case Qt::TopDockWidgetArea:
case Qt::BottomDockWidgetArea:
addDockWidget(area, dw);
break;
default:
if (!restoreDockWidget(dw)) {
QMessageBox::warning(this, QString(), tr("Failed to restore dock widget"));
delete dw;
return;
}
break;
}
extraDockWidgets.append(dw);
destroyDockWidgetMenu->setEnabled(true);
destroyDockWidgetMenu->addAction(new QAction(name, this));
}
void MainWindow::destroyDockWidget(QAction *action)
{
auto index = destroyDockWidgetMenu->actions().indexOf(action);
delete extraDockWidgets.takeAt(index);
destroyDockWidgetMenu->removeAction(action);
action->deleteLater();
if (destroyDockWidgetMenu->isEmpty())
destroyDockWidgetMenu->setEnabled(false);
}
void MainWindow::about()
{
QMessageBox::about(this, tr("About MainWindows"), message);
}

View File

@ -0,0 +1,50 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMap>
#include <QString>
#include <QSize>
class ToolBar;
QT_FORWARD_DECLARE_CLASS(QMenu)
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
typedef QMap<QString, QSize> CustomSizeHintMap;
explicit MainWindow(const CustomSizeHintMap &customSizeHints,
QWidget *parent = nullptr,
Qt::WindowFlags flags = { });
public slots:
void actionTriggered(QAction *action);
void saveLayout();
void loadLayout();
void switchLayoutDirection();
void setDockOptions();
void createDockWidget();
void destroyDockWidget(QAction *action);
void about();
private:
void setupToolBar();
void setupMenuBar();
void setupDockWidgets(const CustomSizeHintMap &customSizeHints);
QList<ToolBar*> toolBars;
QMenu *dockWidgetMenu;
QMenu *mainWindowMenu;
QList<QDockWidget *> extraDockWidgets;
QMenu *destroyDockWidgetMenu;
};
#endif // MAINWINDOW_H

View File

@ -0,0 +1,18 @@
TEMPLATE = app
QT += widgets
requires(qtConfig(combobox))
HEADERS += colorswatch.h mainwindow.h toolbar.h
SOURCES += colorswatch.cpp mainwindow.cpp toolbar.cpp main.cpp
build_all:!build_pass {
CONFIG -= build_all
CONFIG += release
}
#! [qrc]
RESOURCES += mainwindow.qrc
#! [qrc]
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/mainwindows/mainwindow
INSTALLS += target

View File

@ -0,0 +1,8 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/res">
<file>qt.png</file>
<file>titlebarLeft.png</file>
<file>titlebarCenter.png</file>
<file>titlebarRight.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,308 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "toolbar.h"
#include <QRandomGenerator>
#include <QActionGroup>
#include <QMainWindow>
#include <QMenu>
#include <QPainter>
#include <QPainterPath>
#include <QSpinBox>
#include <QLabel>
#include <QToolTip>
#include <stdlib.h>
static QPixmap genIcon(const QSize &iconSize, const QString &, const QColor &color, qreal pixelRatio)
{
int w = qRound(iconSize.width() * pixelRatio);
int h = qRound(iconSize.height() * pixelRatio);
QImage image(w, h, QImage::Format_ARGB32_Premultiplied);
image.fill(0);
QPainter p(&image);
extern void render_qt_text(QPainter *, int, int, const QColor &);
render_qt_text(&p, w, h, color);
QPixmap pm = QPixmap::fromImage(image, Qt::DiffuseDither | Qt::DiffuseAlphaDither);
pm.setDevicePixelRatio(pixelRatio);
return pm;
}
static QPixmap genIcon(const QSize &iconSize, int number, const QColor &color, qreal pixelRatio)
{ return genIcon(iconSize, QString::number(number), color, pixelRatio); }
ToolBar::ToolBar(const QString &title, QMainWindow *mainWindow)
: QToolBar(mainWindow)
, mainWindow(mainWindow)
, spinbox(nullptr)
, spinboxAction(nullptr)
{
setWindowTitle(title);
setObjectName(title);
setIconSize(QSize(32, 32));
qreal dpr = devicePixelRatio();
menu = new QMenu("One", this);
menu->setIcon(genIcon(iconSize(), 1, Qt::black, dpr));
menu->addAction(genIcon(iconSize(), "A", Qt::blue, dpr), "A");
menu->addAction(genIcon(iconSize(), "B", Qt::blue, dpr), "B");
menu->addAction(genIcon(iconSize(), "C", Qt::blue, dpr), "C");
addAction(menu->menuAction());
QAction *two = addAction(genIcon(iconSize(), 2, Qt::white, dpr), "Two");
QFont boldFont;
boldFont.setBold(true);
two->setFont(boldFont);
addAction(genIcon(iconSize(), 3, Qt::red, dpr), "Three");
addAction(genIcon(iconSize(), 4, Qt::green, dpr), "Four");
addAction(genIcon(iconSize(), 5, Qt::blue, dpr), "Five");
addAction(genIcon(iconSize(), 6, Qt::yellow, dpr), "Six");
orderAction = new QAction(this);
orderAction->setText(tr("Order Items in Tool Bar"));
connect(orderAction, &QAction::triggered, this, &ToolBar::order);
randomizeAction = new QAction(this);
randomizeAction->setText(tr("Randomize Items in Tool Bar"));
connect(randomizeAction, &QAction::triggered, this, &ToolBar::randomize);
addSpinBoxAction = new QAction(this);
addSpinBoxAction->setText(tr("Add Spin Box"));
connect(addSpinBoxAction, &QAction::triggered, this, &ToolBar::addSpinBox);
removeSpinBoxAction = new QAction(this);
removeSpinBoxAction->setText(tr("Remove Spin Box"));
removeSpinBoxAction->setEnabled(false);
connect(removeSpinBoxAction, &QAction::triggered, this, &ToolBar::removeSpinBox);
movableAction = new QAction(tr("Movable"), this);
movableAction->setCheckable(true);
connect(movableAction, &QAction::triggered, this, &ToolBar::changeMovable);
allowedAreasActions = new QActionGroup(this);
allowedAreasActions->setExclusive(false);
allowLeftAction = new QAction(tr("Allow on Left"), this);
allowLeftAction->setCheckable(true);
connect(allowLeftAction, &QAction::triggered, this, &ToolBar::allowLeft);
allowRightAction = new QAction(tr("Allow on Right"), this);
allowRightAction->setCheckable(true);
connect(allowRightAction, &QAction::triggered, this, &ToolBar::allowRight);
allowTopAction = new QAction(tr("Allow on Top"), this);
allowTopAction->setCheckable(true);
connect(allowTopAction, &QAction::triggered, this, &ToolBar::allowTop);
allowBottomAction = new QAction(tr("Allow on Bottom"), this);
allowBottomAction->setCheckable(true);
connect(allowBottomAction, &QAction::triggered, this, &ToolBar::allowBottom);
allowedAreasActions->addAction(allowLeftAction);
allowedAreasActions->addAction(allowRightAction);
allowedAreasActions->addAction(allowTopAction);
allowedAreasActions->addAction(allowBottomAction);
areaActions = new QActionGroup(this);
areaActions->setExclusive(true);
leftAction = new QAction(tr("Place on Left") , this);
leftAction->setCheckable(true);
connect(leftAction, &QAction::triggered, this, &ToolBar::placeLeft);
rightAction = new QAction(tr("Place on Right") , this);
rightAction->setCheckable(true);
connect(rightAction, &QAction::triggered, this, &ToolBar::placeRight);
topAction = new QAction(tr("Place on Top") , this);
topAction->setCheckable(true);
connect(topAction, &QAction::triggered, this, &ToolBar::placeTop);
bottomAction = new QAction(tr("Place on Bottom") , this);
bottomAction->setCheckable(true);
connect(bottomAction, &QAction::triggered, this, &ToolBar::placeBottom);
areaActions->addAction(leftAction);
areaActions->addAction(rightAction);
areaActions->addAction(topAction);
areaActions->addAction(bottomAction);
connect(movableAction, &QAction::triggered, areaActions, &QActionGroup::setEnabled);
connect(movableAction, &QAction::triggered, allowedAreasActions, &QActionGroup::setEnabled);
menu = new QMenu(title, this);
menu->addAction(toggleViewAction());
menu->addSeparator();
menu->addAction(orderAction);
menu->addAction(randomizeAction);
menu->addSeparator();
menu->addAction(addSpinBoxAction);
menu->addAction(removeSpinBoxAction);
menu->addSeparator();
menu->addAction(movableAction);
menu->addSeparator();
menu->addActions(allowedAreasActions->actions());
menu->addSeparator();
menu->addActions(areaActions->actions());
menu->addSeparator();
menu->addAction(tr("Insert break"), this, &ToolBar::insertToolBarBreak);
connect(menu, &QMenu::aboutToShow, this, &ToolBar::updateMenu);
randomize();
}
void ToolBar::updateMenu()
{
const Qt::ToolBarArea area = mainWindow->toolBarArea(this);
const Qt::ToolBarAreas areas = allowedAreas();
movableAction->setChecked(isMovable());
allowLeftAction->setChecked(isAreaAllowed(Qt::LeftToolBarArea));
allowRightAction->setChecked(isAreaAllowed(Qt::RightToolBarArea));
allowTopAction->setChecked(isAreaAllowed(Qt::TopToolBarArea));
allowBottomAction->setChecked(isAreaAllowed(Qt::BottomToolBarArea));
if (allowedAreasActions->isEnabled()) {
allowLeftAction->setEnabled(area != Qt::LeftToolBarArea);
allowRightAction->setEnabled(area != Qt::RightToolBarArea);
allowTopAction->setEnabled(area != Qt::TopToolBarArea);
allowBottomAction->setEnabled(area != Qt::BottomToolBarArea);
}
leftAction->setChecked(area == Qt::LeftToolBarArea);
rightAction->setChecked(area == Qt::RightToolBarArea);
topAction->setChecked(area == Qt::TopToolBarArea);
bottomAction->setChecked(area == Qt::BottomToolBarArea);
if (areaActions->isEnabled()) {
leftAction->setEnabled(areas & Qt::LeftToolBarArea);
rightAction->setEnabled(areas & Qt::RightToolBarArea);
topAction->setEnabled(areas & Qt::TopToolBarArea);
bottomAction->setEnabled(areas & Qt::BottomToolBarArea);
}
}
void ToolBar::order()
{
QList<QAction *> ordered;
QList<QAction *> actions1 = actions();
const QList<QAction *> childActions = findChildren<QAction *>();
for (QAction *action : childActions) {
if (!actions1.contains(action))
continue;
actions1.removeAll(action);
ordered.append(action);
}
clear();
addActions(ordered);
orderAction->setEnabled(false);
}
void ToolBar::randomize()
{
QList<QAction *> randomized;
QList<QAction *> actions = this->actions();
while (!actions.isEmpty()) {
QAction *action = actions.takeAt(QRandomGenerator::global()->bounded(actions.size()));
randomized.append(action);
}
clear();
addActions(randomized);
orderAction->setEnabled(true);
}
void ToolBar::addSpinBox()
{
if (!spinbox)
spinbox = new QSpinBox(this);
if (!spinboxAction)
spinboxAction = addWidget(spinbox);
else
addAction(spinboxAction);
addSpinBoxAction->setEnabled(false);
removeSpinBoxAction->setEnabled(true);
}
void ToolBar::removeSpinBox()
{
if (spinboxAction)
removeAction(spinboxAction);
addSpinBoxAction->setEnabled(true);
removeSpinBoxAction->setEnabled(false);
}
void ToolBar::allow(Qt::ToolBarArea area, bool a)
{
Qt::ToolBarAreas areas = allowedAreas();
areas = a ? areas | area : areas & ~area;
setAllowedAreas(areas);
if (areaActions->isEnabled()) {
leftAction->setEnabled(areas & Qt::LeftToolBarArea);
rightAction->setEnabled(areas & Qt::RightToolBarArea);
topAction->setEnabled(areas & Qt::TopToolBarArea);
bottomAction->setEnabled(areas & Qt::BottomToolBarArea);
}
}
void ToolBar::place(Qt::ToolBarArea area, bool p)
{
if (!p)
return;
mainWindow->addToolBar(area, this);
if (allowedAreasActions->isEnabled()) {
allowLeftAction->setEnabled(area != Qt::LeftToolBarArea);
allowRightAction->setEnabled(area != Qt::RightToolBarArea);
allowTopAction->setEnabled(area != Qt::TopToolBarArea);
allowBottomAction->setEnabled(area != Qt::BottomToolBarArea);
}
}
void ToolBar::changeMovable(bool movable)
{ setMovable(movable); }
void ToolBar::allowLeft(bool a)
{ allow(Qt::LeftToolBarArea, a); }
void ToolBar::allowRight(bool a)
{ allow(Qt::RightToolBarArea, a); }
void ToolBar::allowTop(bool a)
{ allow(Qt::TopToolBarArea, a); }
void ToolBar::allowBottom(bool a)
{ allow(Qt::BottomToolBarArea, a); }
void ToolBar::placeLeft(bool p)
{ place(Qt::LeftToolBarArea, p); }
void ToolBar::placeRight(bool p)
{ place(Qt::RightToolBarArea, p); }
void ToolBar::placeTop(bool p)
{ place(Qt::TopToolBarArea, p); }
void ToolBar::placeBottom(bool p)
{ place(Qt::BottomToolBarArea, p); }
void ToolBar::insertToolBarBreak()
{
mainWindow->insertToolBarBreak(this);
}

View File

@ -0,0 +1,74 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef TOOLBAR_H
#define TOOLBAR_H
#include <QToolBar>
QT_FORWARD_DECLARE_CLASS(QAction)
QT_FORWARD_DECLARE_CLASS(QActionGroup)
QT_FORWARD_DECLARE_CLASS(QMenu)
QT_FORWARD_DECLARE_CLASS(QSpinBox)
class ToolBar : public QToolBar
{
Q_OBJECT
public:
explicit ToolBar(const QString &title, QMainWindow *mainWindow);
QMenu *toolbarMenu() const { return menu; }
private slots:
void order();
void randomize();
void addSpinBox();
void removeSpinBox();
void changeMovable(bool movable);
void allowLeft(bool a);
void allowRight(bool a);
void allowTop(bool a);
void allowBottom(bool a);
void placeLeft(bool p);
void placeRight(bool p);
void placeTop(bool p);
void placeBottom(bool p);
void updateMenu();
void insertToolBarBreak();
private:
void allow(Qt::ToolBarArea area, bool allow);
void place(Qt::ToolBarArea area, bool place);
QMainWindow *mainWindow;
QSpinBox *spinbox;
QAction *spinboxAction;
QMenu *menu;
QAction *orderAction;
QAction *randomizeAction;
QAction *addSpinBoxAction;
QAction *removeSpinBoxAction;
QAction *movableAction;
QActionGroup *allowedAreasActions;
QAction *allowLeftAction;
QAction *allowRightAction;
QAction *allowTopAction;
QAction *allowBottomAction;
QActionGroup *areaActions;
QAction *leftAction;
QAction *rightAction;
QAction *topAction;
QAction *bottomAction;
};
#endif // TOOLBAR_H

View File

@ -0,0 +1,55 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(mdi LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/mainwindows/mdi")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(mdi
main.cpp
mainwindow.cpp mainwindow.h
mdichild.cpp mdichild.h
)
set_target_properties(mdi PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(mdi PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
# Resources:
set(mdi_resource_files
"images/copy.png"
"images/cut.png"
"images/new.png"
"images/open.png"
"images/paste.png"
"images/save.png"
)
qt_add_resources(mdi "mdi"
PREFIX
"/"
FILES
${mdi_resource_files}
)
install(TARGETS mdi
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 852 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,29 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QApplication>
#include <QCommandLineParser>
#include <QCommandLineOption>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QCoreApplication::setApplicationName("MDI Example");
QCoreApplication::setOrganizationName("QtProject");
QCoreApplication::setApplicationVersion(QT_VERSION_STR);
QCommandLineParser parser;
parser.setApplicationDescription("Qt MDI Example");
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument("file", "The file to open.");
parser.process(app);
MainWindow mainWin;
const QStringList posArgs = parser.positionalArguments();
for (const QString &fileName : posArgs)
mainWin.openFile(fileName);
mainWin.show();
return app.exec();
}

View File

@ -0,0 +1,463 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "mainwindow.h"
#include "mdichild.h"
MainWindow::MainWindow()
: mdiArea(new QMdiArea)
{
mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
setCentralWidget(mdiArea);
connect(mdiArea, &QMdiArea::subWindowActivated,
this, &MainWindow::updateMenus);
createActions();
createStatusBar();
updateMenus();
readSettings();
setWindowTitle(tr("MDI"));
setUnifiedTitleAndToolBarOnMac(true);
}
void MainWindow::closeEvent(QCloseEvent *event)
{
mdiArea->closeAllSubWindows();
if (mdiArea->currentSubWindow()) {
event->ignore();
} else {
writeSettings();
event->accept();
}
}
void MainWindow::newFile()
{
MdiChild *child = createMdiChild();
child->newFile();
child->show();
}
void MainWindow::open()
{
const QString fileName = QFileDialog::getOpenFileName(this);
if (!fileName.isEmpty())
openFile(fileName);
}
bool MainWindow::openFile(const QString &fileName)
{
if (QMdiSubWindow *existing = findMdiChild(fileName)) {
mdiArea->setActiveSubWindow(existing);
return true;
}
const bool succeeded = loadFile(fileName);
if (succeeded)
statusBar()->showMessage(tr("File loaded"), 2000);
return succeeded;
}
bool MainWindow::loadFile(const QString &fileName)
{
MdiChild *child = createMdiChild();
const bool succeeded = child->loadFile(fileName);
if (succeeded)
child->show();
else
child->close();
MainWindow::prependToRecentFiles(fileName);
return succeeded;
}
static inline QString recentFilesKey() { return QStringLiteral("recentFileList"); }
static inline QString fileKey() { return QStringLiteral("file"); }
static QStringList readRecentFiles(QSettings &settings)
{
QStringList result;
const int count = settings.beginReadArray(recentFilesKey());
for (int i = 0; i < count; ++i) {
settings.setArrayIndex(i);
result.append(settings.value(fileKey()).toString());
}
settings.endArray();
return result;
}
static void writeRecentFiles(const QStringList &files, QSettings &settings)
{
const int count = files.size();
settings.beginWriteArray(recentFilesKey());
for (int i = 0; i < count; ++i) {
settings.setArrayIndex(i);
settings.setValue(fileKey(), files.at(i));
}
settings.endArray();
}
bool MainWindow::hasRecentFiles()
{
QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
const int count = settings.beginReadArray(recentFilesKey());
settings.endArray();
return count > 0;
}
void MainWindow::prependToRecentFiles(const QString &fileName)
{
QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
const QStringList oldRecentFiles = readRecentFiles(settings);
QStringList recentFiles = oldRecentFiles;
recentFiles.removeAll(fileName);
recentFiles.prepend(fileName);
if (oldRecentFiles != recentFiles)
writeRecentFiles(recentFiles, settings);
setRecentFilesVisible(!recentFiles.isEmpty());
}
void MainWindow::setRecentFilesVisible(bool visible)
{
recentFileSubMenuAct->setVisible(visible);
recentFileSeparator->setVisible(visible);
}
void MainWindow::updateRecentFileActions()
{
QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
const QStringList recentFiles = readRecentFiles(settings);
const int count = qMin(int(MaxRecentFiles), recentFiles.size());
int i = 0;
for ( ; i < count; ++i) {
const QString fileName = QFileInfo(recentFiles.at(i)).fileName();
recentFileActs[i]->setText(tr("&%1 %2").arg(i + 1).arg(fileName));
recentFileActs[i]->setData(recentFiles.at(i));
recentFileActs[i]->setVisible(true);
}
for ( ; i < MaxRecentFiles; ++i)
recentFileActs[i]->setVisible(false);
}
void MainWindow::openRecentFile()
{
if (const QAction *action = qobject_cast<const QAction *>(sender()))
openFile(action->data().toString());
}
void MainWindow::save()
{
if (activeMdiChild() && activeMdiChild()->save())
statusBar()->showMessage(tr("File saved"), 2000);
}
void MainWindow::saveAs()
{
MdiChild *child = activeMdiChild();
if (child && child->saveAs()) {
statusBar()->showMessage(tr("File saved"), 2000);
MainWindow::prependToRecentFiles(child->currentFile());
}
}
#ifndef QT_NO_CLIPBOARD
void MainWindow::cut()
{
if (activeMdiChild())
activeMdiChild()->cut();
}
void MainWindow::copy()
{
if (activeMdiChild())
activeMdiChild()->copy();
}
void MainWindow::paste()
{
if (activeMdiChild())
activeMdiChild()->paste();
}
#endif
void MainWindow::about()
{
QMessageBox::about(this, tr("About MDI"),
tr("The <b>MDI</b> example demonstrates how to write multiple "
"document interface applications using Qt."));
}
void MainWindow::updateMenus()
{
bool hasMdiChild = (activeMdiChild() != nullptr);
saveAct->setEnabled(hasMdiChild);
saveAsAct->setEnabled(hasMdiChild);
#ifndef QT_NO_CLIPBOARD
pasteAct->setEnabled(hasMdiChild);
#endif
closeAct->setEnabled(hasMdiChild);
closeAllAct->setEnabled(hasMdiChild);
tileAct->setEnabled(hasMdiChild);
cascadeAct->setEnabled(hasMdiChild);
nextAct->setEnabled(hasMdiChild);
previousAct->setEnabled(hasMdiChild);
windowMenuSeparatorAct->setVisible(hasMdiChild);
#ifndef QT_NO_CLIPBOARD
bool hasSelection = (activeMdiChild() &&
activeMdiChild()->textCursor().hasSelection());
cutAct->setEnabled(hasSelection);
copyAct->setEnabled(hasSelection);
#endif
}
void MainWindow::updateWindowMenu()
{
windowMenu->clear();
windowMenu->addAction(closeAct);
windowMenu->addAction(closeAllAct);
windowMenu->addSeparator();
windowMenu->addAction(tileAct);
windowMenu->addAction(cascadeAct);
windowMenu->addSeparator();
windowMenu->addAction(nextAct);
windowMenu->addAction(previousAct);
windowMenu->addAction(windowMenuSeparatorAct);
QList<QMdiSubWindow *> windows = mdiArea->subWindowList();
windowMenuSeparatorAct->setVisible(!windows.isEmpty());
for (int i = 0; i < windows.size(); ++i) {
QMdiSubWindow *mdiSubWindow = windows.at(i);
MdiChild *child = qobject_cast<MdiChild *>(mdiSubWindow->widget());
QString text;
if (i < 9) {
text = tr("&%1 %2").arg(i + 1)
.arg(child->userFriendlyCurrentFile());
} else {
text = tr("%1 %2").arg(i + 1)
.arg(child->userFriendlyCurrentFile());
}
QAction *action = windowMenu->addAction(text, mdiSubWindow, [this, mdiSubWindow]() {
mdiArea->setActiveSubWindow(mdiSubWindow);
});
action->setCheckable(true);
action ->setChecked(child == activeMdiChild());
}
}
MdiChild *MainWindow::createMdiChild()
{
MdiChild *child = new MdiChild;
mdiArea->addSubWindow(child);
#ifndef QT_NO_CLIPBOARD
connect(child, &QTextEdit::copyAvailable, cutAct, &QAction::setEnabled);
connect(child, &QTextEdit::copyAvailable, copyAct, &QAction::setEnabled);
#endif
return child;
}
void MainWindow::createActions()
{
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
QToolBar *fileToolBar = addToolBar(tr("File"));
const QIcon newIcon = QIcon::fromTheme("document-new", QIcon(":/images/new.png"));
newAct = new QAction(newIcon, tr("&New"), this);
newAct->setShortcuts(QKeySequence::New);
newAct->setStatusTip(tr("Create a new file"));
connect(newAct, &QAction::triggered, this, &MainWindow::newFile);
fileMenu->addAction(newAct);
fileToolBar->addAction(newAct);
//! [qaction setup]
const QIcon openIcon = QIcon::fromTheme("document-open", QIcon(":/images/open.png"));
QAction *openAct = new QAction(openIcon, tr("&Open..."), this);
openAct->setShortcuts(QKeySequence::Open);
openAct->setStatusTip(tr("Open an existing file"));
connect(openAct, &QAction::triggered, this, &MainWindow::open);
fileMenu->addAction(openAct);
fileToolBar->addAction(openAct);
//! [qaction setup]
const QIcon saveIcon = QIcon::fromTheme("document-save", QIcon(":/images/save.png"));
saveAct = new QAction(saveIcon, tr("&Save"), this);
saveAct->setShortcuts(QKeySequence::Save);
saveAct->setStatusTip(tr("Save the document to disk"));
connect(saveAct, &QAction::triggered, this, &MainWindow::save);
fileToolBar->addAction(saveAct);
const QIcon saveAsIcon = QIcon::fromTheme("document-save-as");
saveAsAct = new QAction(saveAsIcon, tr("Save &As..."), this);
saveAsAct->setShortcuts(QKeySequence::SaveAs);
saveAsAct->setStatusTip(tr("Save the document under a new name"));
connect(saveAsAct, &QAction::triggered, this, &MainWindow::saveAs);
fileMenu->addAction(saveAsAct);
fileMenu->addSeparator();
QMenu *recentMenu = fileMenu->addMenu(tr("Recent..."));
connect(recentMenu, &QMenu::aboutToShow, this, &MainWindow::updateRecentFileActions);
recentFileSubMenuAct = recentMenu->menuAction();
for (int i = 0; i < MaxRecentFiles; ++i) {
recentFileActs[i] = recentMenu->addAction(QString(), this, &MainWindow::openRecentFile);
recentFileActs[i]->setVisible(false);
}
recentFileSeparator = fileMenu->addSeparator();
setRecentFilesVisible(MainWindow::hasRecentFiles());
fileMenu->addAction(tr("Switch layout direction"), this, &MainWindow::switchLayoutDirection);
fileMenu->addSeparator();
//! [0]
const QIcon exitIcon = QIcon::fromTheme("application-exit");
QAction *exitAct = fileMenu->addAction(exitIcon, tr("E&xit"), qApp, &QApplication::quit);
exitAct->setShortcuts(QKeySequence::Quit);
exitAct->setStatusTip(tr("Exit the application"));
fileMenu->addAction(exitAct);
//! [0]
#ifndef QT_NO_CLIPBOARD
QMenu *editMenu = menuBar()->addMenu(tr("&Edit"));
QToolBar *editToolBar = addToolBar(tr("Edit"));
const QIcon cutIcon = QIcon::fromTheme("edit-cut", QIcon(":/images/cut.png"));
cutAct = new QAction(cutIcon, tr("Cu&t"), this);
cutAct->setShortcuts(QKeySequence::Cut);
cutAct->setStatusTip(tr("Cut the current selection's contents to the "
"clipboard"));
connect(cutAct, &QAction::triggered, this, &MainWindow::cut);
editMenu->addAction(cutAct);
editToolBar->addAction(cutAct);
const QIcon copyIcon = QIcon::fromTheme("edit-copy", QIcon(":/images/copy.png"));
copyAct = new QAction(copyIcon, tr("&Copy"), this);
copyAct->setShortcuts(QKeySequence::Copy);
copyAct->setStatusTip(tr("Copy the current selection's contents to the "
"clipboard"));
connect(copyAct, &QAction::triggered, this, &MainWindow::copy);
editMenu->addAction(copyAct);
editToolBar->addAction(copyAct);
const QIcon pasteIcon = QIcon::fromTheme("edit-paste", QIcon(":/images/paste.png"));
pasteAct = new QAction(pasteIcon, tr("&Paste"), this);
pasteAct->setShortcuts(QKeySequence::Paste);
pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current "
"selection"));
connect(pasteAct, &QAction::triggered, this, &MainWindow::paste);
editMenu->addAction(pasteAct);
editToolBar->addAction(pasteAct);
#endif
windowMenu = menuBar()->addMenu(tr("&Window"));
connect(windowMenu, &QMenu::aboutToShow, this, &MainWindow::updateWindowMenu);
closeAct = new QAction(tr("Cl&ose"), this);
closeAct->setStatusTip(tr("Close the active window"));
connect(closeAct, &QAction::triggered,
mdiArea, &QMdiArea::closeActiveSubWindow);
closeAllAct = new QAction(tr("Close &All"), this);
closeAllAct->setStatusTip(tr("Close all the windows"));
connect(closeAllAct, &QAction::triggered, mdiArea, &QMdiArea::closeAllSubWindows);
tileAct = new QAction(tr("&Tile"), this);
tileAct->setStatusTip(tr("Tile the windows"));
connect(tileAct, &QAction::triggered, mdiArea, &QMdiArea::tileSubWindows);
cascadeAct = new QAction(tr("&Cascade"), this);
cascadeAct->setStatusTip(tr("Cascade the windows"));
connect(cascadeAct, &QAction::triggered, mdiArea, &QMdiArea::cascadeSubWindows);
nextAct = new QAction(tr("Ne&xt"), this);
nextAct->setShortcuts(QKeySequence::NextChild);
nextAct->setStatusTip(tr("Move the focus to the next window"));
connect(nextAct, &QAction::triggered, mdiArea, &QMdiArea::activateNextSubWindow);
previousAct = new QAction(tr("Pre&vious"), this);
previousAct->setShortcuts(QKeySequence::PreviousChild);
previousAct->setStatusTip(tr("Move the focus to the previous "
"window"));
connect(previousAct, &QAction::triggered, mdiArea, &QMdiArea::activatePreviousSubWindow);
windowMenuSeparatorAct = new QAction(this);
windowMenuSeparatorAct->setSeparator(true);
updateWindowMenu();
menuBar()->addSeparator();
QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
QAction *aboutAct = helpMenu->addAction(tr("&About"), this, &MainWindow::about);
aboutAct->setStatusTip(tr("Show the application's About box"));
QAction *aboutQtAct = helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt);
aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
}
void MainWindow::createStatusBar()
{
statusBar()->showMessage(tr("Ready"));
}
void MainWindow::readSettings()
{
QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
const QByteArray geometry = settings.value("geometry", QByteArray()).toByteArray();
if (geometry.isEmpty()) {
const QRect availableGeometry = screen()->availableGeometry();
resize(availableGeometry.width() / 3, availableGeometry.height() / 2);
move((availableGeometry.width() - width()) / 2,
(availableGeometry.height() - height()) / 2);
} else {
restoreGeometry(geometry);
}
}
void MainWindow::writeSettings()
{
QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
settings.setValue("geometry", saveGeometry());
}
MdiChild *MainWindow::activeMdiChild() const
{
if (QMdiSubWindow *activeSubWindow = mdiArea->activeSubWindow())
return qobject_cast<MdiChild *>(activeSubWindow->widget());
return nullptr;
}
QMdiSubWindow *MainWindow::findMdiChild(const QString &fileName) const
{
QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath();
const QList<QMdiSubWindow *> subWindows = mdiArea->subWindowList();
for (QMdiSubWindow *window : subWindows) {
MdiChild *mdiChild = qobject_cast<MdiChild *>(window->widget());
if (mdiChild->currentFile() == canonicalFilePath)
return window;
}
return nullptr;
}
void MainWindow::switchLayoutDirection()
{
if (layoutDirection() == Qt::LeftToRight)
QGuiApplication::setLayoutDirection(Qt::RightToLeft);
else
QGuiApplication::setLayoutDirection(Qt::LeftToRight);
}

View File

@ -0,0 +1,84 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MdiChild;
QT_BEGIN_NAMESPACE
class QAction;
class QMenu;
class QMdiArea;
class QMdiSubWindow;
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
bool openFile(const QString &fileName);
protected:
void closeEvent(QCloseEvent *event) override;
private slots:
void newFile();
void open();
void save();
void saveAs();
void updateRecentFileActions();
void openRecentFile();
#ifndef QT_NO_CLIPBOARD
void cut();
void copy();
void paste();
#endif
void about();
void updateMenus();
void updateWindowMenu();
MdiChild *createMdiChild();
void switchLayoutDirection();
private:
enum { MaxRecentFiles = 5 };
void createActions();
void createStatusBar();
void readSettings();
void writeSettings();
bool loadFile(const QString &fileName);
static bool hasRecentFiles();
void prependToRecentFiles(const QString &fileName);
void setRecentFilesVisible(bool visible);
MdiChild *activeMdiChild() const;
QMdiSubWindow *findMdiChild(const QString &fileName) const;
QMdiArea *mdiArea;
QMenu *windowMenu;
QAction *newAct;
QAction *saveAct;
QAction *saveAsAct;
QAction *recentFileActs[MaxRecentFiles];
QAction *recentFileSeparator;
QAction *recentFileSubMenuAct;
#ifndef QT_NO_CLIPBOARD
QAction *cutAct;
QAction *copyAct;
QAction *pasteAct;
#endif
QAction *closeAct;
QAction *closeAllAct;
QAction *tileAct;
QAction *cascadeAct;
QAction *nextAct;
QAction *previousAct;
QAction *windowMenuSeparatorAct;
};
#endif

View File

@ -0,0 +1,13 @@
QT += widgets
requires(qtConfig(filedialog))
HEADERS = mainwindow.h \
mdichild.h
SOURCES = main.cpp \
mainwindow.cpp \
mdichild.cpp
RESOURCES = mdi.qrc
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/mainwindows/mdi
INSTALLS += target

View File

@ -0,0 +1,10 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>images/copy.png</file>
<file>images/cut.png</file>
<file>images/new.png</file>
<file>images/open.png</file>
<file>images/paste.png</file>
<file>images/save.png</file>
</qresource>
</RCC>

View File

@ -0,0 +1,150 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "mdichild.h"
MdiChild::MdiChild()
{
setAttribute(Qt::WA_DeleteOnClose);
isUntitled = true;
}
void MdiChild::newFile()
{
static int sequenceNumber = 1;
isUntitled = true;
curFile = tr("document%1.txt").arg(sequenceNumber++);
setWindowTitle(curFile + "[*]");
connect(document(), &QTextDocument::contentsChanged,
this, &MdiChild::documentWasModified);
}
bool MdiChild::loadFile(const QString &fileName)
{
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, tr("MDI"),
tr("Cannot read file %1:\n%2.")
.arg(fileName)
.arg(file.errorString()));
return false;
}
QTextStream in(&file);
QGuiApplication::setOverrideCursor(Qt::WaitCursor);
setPlainText(in.readAll());
QGuiApplication::restoreOverrideCursor();
setCurrentFile(fileName);
connect(document(), &QTextDocument::contentsChanged,
this, &MdiChild::documentWasModified);
return true;
}
bool MdiChild::save()
{
if (isUntitled) {
return saveAs();
} else {
return saveFile(curFile);
}
}
bool MdiChild::saveAs()
{
QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"),
curFile);
if (fileName.isEmpty())
return false;
return saveFile(fileName);
}
bool MdiChild::saveFile(const QString &fileName)
{
QString errorMessage;
QGuiApplication::setOverrideCursor(Qt::WaitCursor);
QSaveFile file(fileName);
if (file.open(QFile::WriteOnly | QFile::Text)) {
QTextStream out(&file);
out << toPlainText();
if (!file.commit()) {
errorMessage = tr("Cannot write file %1:\n%2.")
.arg(QDir::toNativeSeparators(fileName), file.errorString());
}
} else {
errorMessage = tr("Cannot open file %1 for writing:\n%2.")
.arg(QDir::toNativeSeparators(fileName), file.errorString());
}
QGuiApplication::restoreOverrideCursor();
if (!errorMessage.isEmpty()) {
QMessageBox::warning(this, tr("MDI"), errorMessage);
return false;
}
setCurrentFile(fileName);
return true;
}
QString MdiChild::userFriendlyCurrentFile()
{
return strippedName(curFile);
}
void MdiChild::closeEvent(QCloseEvent *event)
{
if (maybeSave()) {
event->accept();
} else {
event->ignore();
}
}
void MdiChild::documentWasModified()
{
setWindowModified(document()->isModified());
}
bool MdiChild::maybeSave()
{
if (!document()->isModified())
return true;
const QMessageBox::StandardButton ret
= QMessageBox::warning(this, tr("MDI"),
tr("'%1' has been modified.\n"
"Do you want to save your changes?")
.arg(userFriendlyCurrentFile()),
QMessageBox::Save | QMessageBox::Discard
| QMessageBox::Cancel);
switch (ret) {
case QMessageBox::Save:
return save();
case QMessageBox::Cancel:
return false;
default:
break;
}
return true;
}
void MdiChild::setCurrentFile(const QString &fileName)
{
curFile = QFileInfo(fileName).canonicalFilePath();
isUntitled = false;
document()->setModified(false);
setWindowModified(false);
setWindowTitle(userFriendlyCurrentFile() + "[*]");
}
QString MdiChild::strippedName(const QString &fullFileName)
{
return QFileInfo(fullFileName).fileName();
}

View File

@ -0,0 +1,39 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef MDICHILD_H
#define MDICHILD_H
#include <QTextEdit>
class MdiChild : public QTextEdit
{
Q_OBJECT
public:
MdiChild();
void newFile();
bool loadFile(const QString &fileName);
bool save();
bool saveAs();
bool saveFile(const QString &fileName);
QString userFriendlyCurrentFile();
QString currentFile() { return curFile; }
protected:
void closeEvent(QCloseEvent *event) override;
private slots:
void documentWasModified();
private:
bool maybeSave();
void setCurrentFile(const QString &fileName);
QString strippedName(const QString &fullFileName);
QString curFile;
bool isUntitled;
};
#endif