mainwindow.cpp Example File

widgets/icons/mainwindow.cpp
/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/
#include <QtWidgets> #include "iconpreviewarea.h" #include "iconsizespinbox.h" #include "imagedelegate.h" #include "mainwindow.h" enum { OtherSize = QStyle::PM_CustomBase }; MainWindow::MainWindow() { QWidget *centralWidget = new QWidget(this); setCentralWidget(centralWidget); createActions(); QGridLayout *mainLayout = new QGridLayout(centralWidget); QGroupBox *previewGroupBox = new QGroupBox(tr("Preview")); previewArea = new IconPreviewArea(previewGroupBox); QVBoxLayout *previewLayout = new QVBoxLayout(previewGroupBox); previewLayout->addWidget(previewArea); mainLayout->addWidget(previewGroupBox, 0, 0, 1, 2); mainLayout->addWidget(createImagesGroupBox(), 1, 0); QVBoxLayout *vBox = new QVBoxLayout; vBox->addWidget(createIconSizeGroupBox()); vBox->addWidget(createHighDpiIconSizeGroupBox()); vBox->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding)); mainLayout->addLayout(vBox, 1, 1); createContextMenu(); setWindowTitle(tr("Icons")); checkCurrentStyle(); sizeButtonGroup->button(OtherSize)->click(); } void MainWindow::show() { QMainWindow::show(); connect(windowHandle(), &QWindow::screenChanged, this, &MainWindow::screenChanged); screenChanged(); } void MainWindow::about() { QMessageBox::about(this, tr("About Icons"), tr("The <b>Icons</b> example illustrates how Qt renders an icon in " "different modes (active, normal, disabled, and selected) and " "states (on and off) based on a set of images.")); } void MainWindow::changeStyle(bool checked) { if (!checked) return; const QAction *action = qobject_cast<QAction *>(sender()); QStyle *style = QStyleFactory::create(action->data().toString()); Q_ASSERT(style); QApplication::setStyle(style); foreach (QAbstractButton *button, sizeButtonGroup->buttons()) { const QStyle::PixelMetric metric = static_cast<QStyle::PixelMetric>(sizeButtonGroup->id(button)); const int value = style->pixelMetric(metric); switch (metric) { case QStyle::PM_SmallIconSize: button->setText(tr("Small (%1 x %1)").arg(value)); break; case QStyle::PM_LargeIconSize: button->setText(tr("Large (%1 x %1)").arg(value)); break; case QStyle::PM_ToolBarIconSize: button->setText(tr("Toolbars (%1 x %1)").arg(value)); break; case QStyle::PM_ListViewIconSize: button->setText(tr("List views (%1 x %1)").arg(value)); break; case QStyle::PM_IconViewIconSize: button->setText(tr("Icon views (%1 x %1)").arg(value)); break; case QStyle::PM_TabBarIconSize: button->setText(tr("Tab bars (%1 x %1)").arg(value)); break; default: break; } } triggerChangeSize(); } void MainWindow::changeSize(int id, bool checked) { if (!checked) return; const bool other = id == int(OtherSize); const int extent = other ? otherSpinBox->value() : QApplication::style()->pixelMetric(static_cast<QStyle::PixelMetric>(id)); previewArea->setSize(QSize(extent, extent)); otherSpinBox->setEnabled(other); } void MainWindow::triggerChangeSize() { changeSize(sizeButtonGroup->checkedId(), true); } void MainWindow::changeIcon() { QIcon icon; for (int row = 0; row < imagesTable->rowCount(); ++row) { const QTableWidgetItem *fileItem = imagesTable->item(row, 0); const QTableWidgetItem *modeItem = imagesTable->item(row, 1); const QTableWidgetItem *stateItem = imagesTable->item(row, 2); if (fileItem->checkState() == Qt::Checked) { const int modeIndex = IconPreviewArea::iconModeNames().indexOf(modeItem->text()); Q_ASSERT(modeIndex >= 0); const int stateIndex = IconPreviewArea::iconStateNames().indexOf(stateItem->text()); Q_ASSERT(stateIndex >= 0); const QIcon::Mode mode = IconPreviewArea::iconModes().at(modeIndex); const QIcon::State state = IconPreviewArea::iconStates().at(stateIndex); const QString fileName = fileItem->data(Qt::UserRole).toString(); QImage image(fileName); if (!image.isNull()) icon.addPixmap(QPixmap::fromImage(image), mode, state); } } previewArea->setIcon(icon); } void MainWindow::addSampleImages() { addImages(QLatin1String(SRCDIR) + QLatin1String("/images")); } void MainWindow::addOtherImages() { static bool firstInvocation = true; QString directory; if (firstInvocation) { firstInvocation = false; directory = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).value(0, QString()); } addImages(directory); } void MainWindow::addImages(const QString &directory) { QFileDialog fileDialog(this, tr("Open Images"), directory); QStringList mimeTypeFilters; foreach (const QByteArray &mimeTypeName, QImageReader::supportedMimeTypes()) mimeTypeFilters.append(mimeTypeName); mimeTypeFilters.sort(); fileDialog.setMimeTypeFilters(mimeTypeFilters); fileDialog.selectMimeTypeFilter(QLatin1String("image/png")); fileDialog.setAcceptMode(QFileDialog::AcceptOpen); fileDialog.setFileMode(QFileDialog::ExistingFiles); if (!nativeFileDialogAct->isChecked()) fileDialog.setOption(QFileDialog::DontUseNativeDialog); if (fileDialog.exec() == QDialog::Accepted) loadImages(fileDialog.selectedFiles()); } void MainWindow::loadImages(const QStringList &fileNames) { foreach (const QString &fileName, fileNames) { const int row = imagesTable->rowCount(); imagesTable->setRowCount(row + 1); const QFileInfo fileInfo(fileName); const QString imageName = fileInfo.baseName(); const QString fileName2x = fileInfo.absolutePath() + QLatin1Char('/') + imageName + QLatin1String("@2x.") + fileInfo.suffix(); const QFileInfo fileInfo2x(fileName2x); const QImage image(fileName); const QString toolTip = tr("Directory: %1\nFile: %2\nFile@2x: %3\nSize: %4x%5") .arg(QDir::toNativeSeparators(fileInfo.absolutePath()), fileInfo.fileName()) .arg(fileInfo2x.exists() ? fileInfo2x.fileName() : tr("<None>")) .arg(image.width()).arg(image.height()); QTableWidgetItem *fileItem = new QTableWidgetItem(imageName); fileItem->setData(Qt::UserRole, fileName); fileItem->setIcon(QPixmap::fromImage(image)); fileItem->setFlags((fileItem->flags() | Qt::ItemIsUserCheckable) & ~Qt::ItemIsEditable); fileItem->setToolTip(toolTip); QIcon::Mode mode = QIcon::Normal; QIcon::State state = QIcon::Off; if (guessModeStateAct->isChecked()) { if (imageName.contains(QLatin1String("_act"), Qt::CaseInsensitive)) mode = QIcon::Active; else if (imageName.contains(QLatin1String("_dis"), Qt::CaseInsensitive)) mode = QIcon::Disabled; else if (imageName.contains(QLatin1String("_sel"), Qt::CaseInsensitive)) mode = QIcon::Selected; if (imageName.contains(QLatin1String("_on"), Qt::CaseInsensitive)) state = QIcon::On; } imagesTable->setItem(row, 0, fileItem); QTableWidgetItem *modeItem = new QTableWidgetItem(IconPreviewArea::iconModeNames().at(IconPreviewArea::iconModes().indexOf(mode))); modeItem->setToolTip(toolTip); imagesTable->setItem(row, 1, modeItem); QTableWidgetItem *stateItem = new QTableWidgetItem(IconPreviewArea::iconStateNames().at(IconPreviewArea::iconStates().indexOf(state))); stateItem->setToolTip(toolTip); imagesTable->setItem(row, 2, stateItem); imagesTable->openPersistentEditor(modeItem); imagesTable->openPersistentEditor(stateItem); fileItem->setCheckState(Qt::Checked); } } void MainWindow::useHighDpiPixmapsChanged(int checkState) { QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, checkState == Qt::Checked); changeIcon(); } void MainWindow::removeAllImages() { imagesTable->setRowCount(0); changeIcon(); } QWidget *MainWindow::createImagesGroupBox() { QGroupBox *imagesGroupBox = new QGroupBox(tr("Images")); imagesTable = new QTableWidget; imagesTable->setSelectionMode(QAbstractItemView::NoSelection); imagesTable->setItemDelegate(new ImageDelegate(this)); QStringList labels; labels << tr("Image") << tr("Mode") << tr("State"); imagesTable->horizontalHeader()->setDefaultSectionSize(90); imagesTable->setColumnCount(3); imagesTable->setHorizontalHeaderLabels(labels); imagesTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); imagesTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed); imagesTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed); imagesTable->verticalHeader()->hide(); connect(imagesTable, &QTableWidget::itemChanged, this, &MainWindow::changeIcon); QVBoxLayout *layout = new QVBoxLayout(imagesGroupBox); layout->addWidget(imagesTable); return imagesGroupBox; } QWidget *MainWindow::createIconSizeGroupBox() { QGroupBox *iconSizeGroupBox = new QGroupBox(tr("Icon Size")); sizeButtonGroup = new QButtonGroup(this); sizeButtonGroup->setExclusive(true); connect(sizeButtonGroup, QOverload<int, bool>::of(&QButtonGroup::buttonToggled), this, &MainWindow::changeSize); QRadioButton *smallRadioButton = new QRadioButton; sizeButtonGroup->addButton(smallRadioButton, QStyle::PM_SmallIconSize); QRadioButton *largeRadioButton = new QRadioButton; sizeButtonGroup->addButton(largeRadioButton, QStyle::PM_LargeIconSize); QRadioButton *toolBarRadioButton = new QRadioButton; sizeButtonGroup->addButton(toolBarRadioButton, QStyle::PM_ToolBarIconSize); QRadioButton *listViewRadioButton = new QRadioButton; sizeButtonGroup->addButton(listViewRadioButton, QStyle::PM_ListViewIconSize); QRadioButton *iconViewRadioButton = new QRadioButton; sizeButtonGroup->addButton(iconViewRadioButton, QStyle::PM_IconViewIconSize); QRadioButton *tabBarRadioButton = new QRadioButton; sizeButtonGroup->addButton(tabBarRadioButton, QStyle::PM_TabBarIconSize); QRadioButton *otherRadioButton = new QRadioButton(tr("Other:")); sizeButtonGroup->addButton(otherRadioButton, OtherSize); otherSpinBox = new IconSizeSpinBox; otherSpinBox->setRange(8, 256); const QString spinBoxToolTip = tr("Enter a custom size within %1..%2") .arg(otherSpinBox->minimum()).arg(otherSpinBox->maximum()); otherSpinBox->setValue(64); otherSpinBox->setToolTip(spinBoxToolTip); otherRadioButton->setToolTip(spinBoxToolTip); connect(otherSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &MainWindow::triggerChangeSize); QHBoxLayout *otherSizeLayout = new QHBoxLayout; otherSizeLayout->addWidget(otherRadioButton); otherSizeLayout->addWidget(otherSpinBox); otherSizeLayout->addStretch(); QGridLayout *layout = new QGridLayout(iconSizeGroupBox); layout->addWidget(smallRadioButton, 0, 0); layout->addWidget(largeRadioButton, 1, 0); layout->addWidget(toolBarRadioButton, 2, 0); layout->addWidget(listViewRadioButton, 0, 1); layout->addWidget(iconViewRadioButton, 1, 1); layout->addWidget(tabBarRadioButton, 2, 1); layout->addLayout(otherSizeLayout, 3, 0, 1, 2); layout->setRowStretch(4, 1); return iconSizeGroupBox; } void MainWindow::screenChanged() { devicePixelRatioLabel->setText(QString::number(devicePixelRatioF())); if (const QWindow *window = windowHandle()) { const QScreen *screen = window->screen(); const QString screenDescription = tr("\"%1\" (%2x%3)").arg(screen->name()) .arg(screen->geometry().width()).arg(screen->geometry().height()); screenNameLabel->setText(screenDescription); } changeIcon(); } QWidget *MainWindow::createHighDpiIconSizeGroupBox() { QGroupBox *highDpiGroupBox = new QGroupBox(tr("High DPI Scaling")); QFormLayout *layout = new QFormLayout(highDpiGroupBox); devicePixelRatioLabel = new QLabel(highDpiGroupBox); screenNameLabel = new QLabel(highDpiGroupBox); layout->addRow(tr("Screen:"), screenNameLabel); layout->addRow(tr("Device pixel ratio:"), devicePixelRatioLabel); QCheckBox *highDpiPixmapsCheckBox = new QCheckBox(QLatin1String("Qt::AA_UseHighDpiPixmaps")); highDpiPixmapsCheckBox->setChecked(QCoreApplication::testAttribute(Qt::AA_UseHighDpiPixmaps)); connect(highDpiPixmapsCheckBox, &QCheckBox::stateChanged, this, &MainWindow::useHighDpiPixmapsChanged); layout->addRow(highDpiPixmapsCheckBox); return highDpiGroupBox; } void MainWindow::createActions() { QMenu *fileMenu = menuBar()->addMenu(tr("&File")); addSampleImagesAct = new QAction(tr("Add &Sample Images..."), this); addSampleImagesAct->setShortcut(tr("Ctrl+A")); connect(addSampleImagesAct, &QAction::triggered, this, &MainWindow::addSampleImages); fileMenu->addAction(addSampleImagesAct); addOtherImagesAct = new QAction(tr("&Add Images..."), this); addOtherImagesAct->setShortcut(QKeySequence::Open); connect(addOtherImagesAct, &QAction::triggered, this, &MainWindow::addOtherImages); fileMenu->addAction(addOtherImagesAct); removeAllImagesAct = new QAction(tr("&Remove All Images"), this); removeAllImagesAct->setShortcut(tr("Ctrl+R")); connect(removeAllImagesAct, &QAction::triggered, this, &MainWindow::removeAllImages); fileMenu->addAction(removeAllImagesAct); fileMenu->addSeparator(); QAction *exitAct = fileMenu->addAction(tr("&Quit"), this, &QWidget::close); exitAct->setShortcuts(QKeySequence::Quit); QMenu *viewMenu = menuBar()->addMenu(tr("&View")); styleActionGroup = new QActionGroup(this); foreach (const QString &styleName, QStyleFactory::keys()) { QAction *action = new QAction(tr("%1 Style").arg(styleName), styleActionGroup); action->setData(styleName); action->setCheckable(true); connect(action, &QAction::triggered, this, &MainWindow::changeStyle); viewMenu->addAction(action); } QMenu *settingsMenu = menuBar()->addMenu(tr("&Settings")); guessModeStateAct = new QAction(tr("&Guess Image Mode/State"), this); guessModeStateAct->setCheckable(true); guessModeStateAct->setChecked(true); settingsMenu->addAction(guessModeStateAct); nativeFileDialogAct = new QAction(tr("&Use Native File Dialog"), this); nativeFileDialogAct->setCheckable(true); nativeFileDialogAct->setChecked(true); settingsMenu->addAction(nativeFileDialogAct); QMenu *helpMenu = menuBar()->addMenu(tr("&Help")); helpMenu->addAction(tr("&About"), this, &MainWindow::about); helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); } void MainWindow::createContextMenu() { imagesTable->setContextMenuPolicy(Qt::ActionsContextMenu); imagesTable->addAction(addSampleImagesAct); imagesTable->addAction(addOtherImagesAct); imagesTable->addAction(removeAllImagesAct); } void MainWindow::checkCurrentStyle() { foreach (QAction *action, styleActionGroup->actions()) { QString styleName = action->data().toString(); QScopedPointer<QStyle> candidate(QStyleFactory::create(styleName)); Q_ASSERT(!candidate.isNull()); if (candidate->metaObject()->className() == QApplication::style()->metaObject()->className()) { action->trigger(); return; } } }