6.5.3 clean
46
tests/manual/examples/corelib/permissions/CMakeLists.txt
Normal file
@ -0,0 +1,46 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(permissions LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/corelib/permissions")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(permissions
|
||||
MANUAL_FINALIZATION
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(permissions PROPERTIES
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "io.qt.examples.permissions"
|
||||
QT_ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android"
|
||||
)
|
||||
|
||||
target_link_libraries(permissions PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
install(TARGETS permissions
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
||||
|
||||
if(APPLE AND NOT CMAKE_GENERATOR STREQUAL "Xcode")
|
||||
add_custom_command(TARGET permissions
|
||||
POST_BUILD COMMAND codesign -s - permissions.app)
|
||||
endif()
|
||||
|
||||
qt_finalize_executable(permissions)
|
59
tests/manual/examples/corelib/permissions/Info.plist
Normal file
@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
|
||||
<key>CFBundleName</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
|
||||
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
|
||||
<key>NSBluetoothAlwaysUsageDescription</key>
|
||||
<string>Testing BluetoothAlways</string>
|
||||
<key>NSCalendarsUsageDescription</key>
|
||||
<string>Testing Calendars</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Testing Camera</string>
|
||||
<key>NSContactsUsageDescription</key>
|
||||
<string>Testing Contacts</string>
|
||||
<key>NSHealthShareUsageDescription</key>
|
||||
<string>Testing HealthShare</string>
|
||||
<key>NSHealthUpdateUsageDescription</key>
|
||||
<string>Testing HealthUpdate</string>
|
||||
<key>NSLocationUsageDescription</key>
|
||||
<string>Testing Location on macOS</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>Testing Location when in use on iOS</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>Testing Location always and when in use on iOS</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Testing Microphone</string>
|
||||
|
||||
</dict>
|
||||
</plist>
|
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.qtproject.example"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="-- %%INSERT_VERSION_CODE%% --"
|
||||
android:versionName="-- %%INSERT_VERSION_NAME%% --">
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
||||
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
|
||||
<!-- %%INSERT_PERMISSIONS -->
|
||||
<!-- %%INSERT_FEATURES -->
|
||||
<supports-screens
|
||||
android:anyDensity="true"
|
||||
android:largeScreens="true"
|
||||
android:normalScreens="true"
|
||||
android:smallScreens="true" />
|
||||
<application
|
||||
android:name="org.qtproject.qt.android.bindings.QtApplication"
|
||||
android:hardwareAccelerated="true"
|
||||
android:label="-- %%INSERT_APP_NAME%% --"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:allowNativeHeapPointerTagging="false"
|
||||
android:allowBackup="true"
|
||||
android:fullBackupOnly="false">
|
||||
<activity
|
||||
android:name="org.qtproject.qt.android.bindings.QtActivity"
|
||||
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
|
||||
android:label="-- %%INSERT_APP_NAME%% --"
|
||||
android:launchMode="singleTop"
|
||||
android:screenOrientation="unspecified"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.app.lib_name"
|
||||
android:value="-- %%INSERT_APP_LIB_NAME%% --" />
|
||||
|
||||
<meta-data
|
||||
android:name="android.app.extract_android_style"
|
||||
android:value="minimal" />
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
87
tests/manual/examples/corelib/permissions/main.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QtCore/qmetaobject.h>
|
||||
#include <QtWidgets/qapplication.h>
|
||||
#include <QtWidgets/qwidget.h>
|
||||
#include <QtWidgets/qpushbutton.h>
|
||||
#include <QtWidgets/qlayout.h>
|
||||
#include <QtWidgets/qmessagebox.h>
|
||||
|
||||
#if !QT_CONFIG(permissions)
|
||||
#error "This example requires the permissions feature, which is not enabled on this platform"
|
||||
#endif
|
||||
|
||||
#include <QtCore/qpermissions.h>
|
||||
|
||||
class PermissionWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PermissionWidget(QWidget *parent = nullptr) : QWidget(parent)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
|
||||
static const QPermission permissions[] = {
|
||||
QCameraPermission{},
|
||||
QMicrophonePermission{},
|
||||
QBluetoothPermission{},
|
||||
QContactsPermission{},
|
||||
QCalendarPermission{},
|
||||
QLocationPermission{}
|
||||
};
|
||||
|
||||
for (auto permission : permissions) {
|
||||
auto permissionName = QString::fromLatin1(permission.type().name());
|
||||
QPushButton *button = new QPushButton(permissionName.sliced(1, permissionName.length() - 11));
|
||||
connect(button, &QPushButton::clicked, this, &PermissionWidget::buttonClicked);
|
||||
button->setProperty("permission", QVariant::fromValue(permission));
|
||||
layout->addWidget(button);
|
||||
}
|
||||
|
||||
QPalette pal = palette();
|
||||
pal.setBrush(QPalette::Window, QGradient(QGradient::HappyAcid));
|
||||
setPalette(pal);
|
||||
}
|
||||
|
||||
private:
|
||||
void buttonClicked()
|
||||
{
|
||||
auto *button = static_cast<QPushButton*>(sender());
|
||||
|
||||
auto permission = button->property("permission").value<QPermission>();
|
||||
Q_ASSERT(permission.type().isValid());
|
||||
|
||||
switch (qApp->checkPermission(permission)) {
|
||||
case Qt::PermissionStatus::Undetermined:
|
||||
qApp->requestPermission(permission, this,
|
||||
[button](const QPermission &permission) {
|
||||
Q_UNUSED(permission);
|
||||
emit button->clicked(); // Try again
|
||||
}
|
||||
);
|
||||
return;
|
||||
case Qt::PermissionStatus::Denied:
|
||||
QMessageBox::warning(this, button->text(),
|
||||
tr("Permission is needed to use %1. Please grant permission "\
|
||||
"to this application in the system settings.").arg(button->text()));
|
||||
return;
|
||||
case Qt::PermissionStatus::Granted:
|
||||
break; // Proceed
|
||||
}
|
||||
|
||||
// All good, can use the feature
|
||||
QMessageBox::information(this, button->text(),
|
||||
tr("Accessing %1").arg(button->text()));
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
PermissionWidget widget;
|
||||
widget.show();
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
#include "main.moc"
|
53
tests/manual/examples/opengl/qopenglwidget/CMakeLists.txt
Normal file
@ -0,0 +1,53 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(qopenglwidget LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/opengl/qopenglwidget")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui OpenGL OpenGLWidgets Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(qopenglwidget
|
||||
bubble.cpp bubble.h
|
||||
glwidget.cpp glwidget.h
|
||||
main.cpp
|
||||
mainwindow.cpp mainwindow.h
|
||||
)
|
||||
|
||||
set_target_properties(qopenglwidget PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(qopenglwidget PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::OpenGL
|
||||
Qt6::OpenGLWidgets
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(texture_resource_files
|
||||
"qt.png"
|
||||
)
|
||||
|
||||
qt6_add_resources(qopenglwidget "texture"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
${texture_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS qopenglwidget
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
99
tests/manual/examples/opengl/qopenglwidget/bubble.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#include "bubble.h"
|
||||
|
||||
Bubble::Bubble(const QPointF &position, qreal radius, const QPointF &velocity)
|
||||
: position(position), vel(velocity), radius(radius)
|
||||
{
|
||||
innerColor = randomColor();
|
||||
outerColor = randomColor();
|
||||
updateBrush();
|
||||
}
|
||||
|
||||
//! [0]
|
||||
void Bubble::updateCache()
|
||||
{
|
||||
delete cache;
|
||||
cache = new QImage(qRound(radius * 2 + 2), qRound(radius * 2 + 2), QImage::Format_ARGB32_Premultiplied);
|
||||
cache->fill(0x00000000);
|
||||
QPainter p(cache);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
QPen pen(Qt::white);
|
||||
pen.setWidth(2);
|
||||
p.setPen(pen);
|
||||
p.setBrush(brush);
|
||||
p.drawEllipse(1, 1, int(2*radius), int(2*radius));
|
||||
}
|
||||
//! [0]
|
||||
|
||||
Bubble::~Bubble()
|
||||
{
|
||||
delete cache;
|
||||
}
|
||||
|
||||
void Bubble::updateBrush()
|
||||
{
|
||||
QRadialGradient gradient(QPointF(radius, radius), radius,
|
||||
QPointF(radius*0.5, radius*0.5));
|
||||
|
||||
gradient.setColorAt(0, QColor(255, 255, 255, 255));
|
||||
gradient.setColorAt(0.25, innerColor);
|
||||
gradient.setColorAt(1, outerColor);
|
||||
brush = QBrush(gradient);
|
||||
updateCache();
|
||||
}
|
||||
|
||||
//! [1]
|
||||
void Bubble::drawBubble(QPainter *painter)
|
||||
{
|
||||
painter->save();
|
||||
painter->translate(position.x() - radius, position.y() - radius);
|
||||
painter->setOpacity(0.8);
|
||||
painter->drawImage(0, 0, *cache);
|
||||
painter->restore();
|
||||
}
|
||||
//! [1]
|
||||
|
||||
QColor Bubble::randomColor()
|
||||
{
|
||||
int red = int(185 + QRandomGenerator::global()->bounded(70));
|
||||
int green = int(185 + QRandomGenerator::global()->bounded(70));
|
||||
int blue = int(205 + QRandomGenerator::global()->bounded(50));
|
||||
int alpha = int(91 + QRandomGenerator::global()->bounded(100));
|
||||
|
||||
return QColor(red, green, blue, alpha);
|
||||
}
|
||||
|
||||
void Bubble::move(const QRect &bbox)
|
||||
{
|
||||
position += vel;
|
||||
qreal leftOverflow = position.x() - radius - bbox.left();
|
||||
qreal rightOverflow = position.x() + radius - bbox.right();
|
||||
qreal topOverflow = position.y() - radius - bbox.top();
|
||||
qreal bottomOverflow = position.y() + radius - bbox.bottom();
|
||||
|
||||
if (leftOverflow < 0.0) {
|
||||
position.setX(position.x() - 2 * leftOverflow);
|
||||
vel.setX(-vel.x());
|
||||
} else if (rightOverflow > 0.0) {
|
||||
position.setX(position.x() - 2 * rightOverflow);
|
||||
vel.setX(-vel.x());
|
||||
}
|
||||
|
||||
if (topOverflow < 0.0) {
|
||||
position.setY(position.y() - 2 * topOverflow);
|
||||
vel.setY(-vel.y());
|
||||
} else if (bottomOverflow > 0.0) {
|
||||
position.setY(position.y() - 2 * bottomOverflow);
|
||||
vel.setY(-vel.y());
|
||||
}
|
||||
}
|
||||
|
||||
QRectF Bubble::rect()
|
||||
{
|
||||
return QRectF(position.x() - radius, position.y() - radius,
|
||||
2 * radius, 2 * radius);
|
||||
}
|
39
tests/manual/examples/opengl/qopenglwidget/bubble.h
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef BUBBLE_H
|
||||
#define BUBBLE_H
|
||||
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
#include <QPointF>
|
||||
#include <QRect>
|
||||
#include <QRectF>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QPainter)
|
||||
|
||||
class Bubble
|
||||
{
|
||||
public:
|
||||
Bubble(const QPointF &position, qreal radius, const QPointF &velocity);
|
||||
~Bubble();
|
||||
|
||||
void drawBubble(QPainter *painter);
|
||||
void updateBrush();
|
||||
void move(const QRect &bbox);
|
||||
void updateCache();
|
||||
QRectF rect();
|
||||
|
||||
private:
|
||||
QColor randomColor();
|
||||
|
||||
QBrush brush;
|
||||
QPointF position;
|
||||
QPointF vel;
|
||||
qreal radius;
|
||||
QColor innerColor;
|
||||
QColor outerColor;
|
||||
QImage *cache = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
540
tests/manual/examples/opengl/qopenglwidget/glwidget.cpp
Normal file
@ -0,0 +1,540 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "glwidget.h"
|
||||
#include <QPainter>
|
||||
#include <QPaintEngine>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QOpenGLTexture>
|
||||
#include <QRandomGenerator>
|
||||
#include <QCoreApplication>
|
||||
#include <qmath.h>
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "bubble.h"
|
||||
|
||||
const int bubbleNum = 8;
|
||||
|
||||
#ifndef GL_SRGB8_ALPHA8
|
||||
#define GL_SRGB8_ALPHA8 0x8C43
|
||||
#endif
|
||||
|
||||
GLWidget::GLWidget(MainWindow *maybeMainWindow, const QColor &background)
|
||||
: m_mainWindow(maybeMainWindow),
|
||||
m_background(background)
|
||||
{
|
||||
setMinimumSize(300, 250);
|
||||
if (QCoreApplication::arguments().contains(QStringLiteral("--srgb")))
|
||||
setTextureFormat(GL_SRGB8_ALPHA8);
|
||||
}
|
||||
|
||||
GLWidget::~GLWidget()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void GLWidget::reset()
|
||||
{
|
||||
qDeleteAll(m_bubbles);
|
||||
// Leave everything in a state suitable for a subsequent call to
|
||||
// initialize(). This matters when coming from the context's
|
||||
// aboutToBeDestroyed signal, would not matter when invoked from the
|
||||
// destructor.
|
||||
m_bubbles.clear();
|
||||
|
||||
// And now release all OpenGL resources.
|
||||
makeCurrent();
|
||||
delete m_texture;
|
||||
m_texture = nullptr;
|
||||
delete m_program1;
|
||||
m_program1 = nullptr;
|
||||
delete m_program2;
|
||||
m_program2 = nullptr;
|
||||
delete m_vshader1;
|
||||
m_vshader1 = nullptr;
|
||||
delete m_fshader1;
|
||||
m_fshader1 = nullptr;
|
||||
delete m_vshader2;
|
||||
m_vshader2 = nullptr;
|
||||
delete m_fshader2;
|
||||
m_fshader2 = nullptr;
|
||||
m_vbo1.destroy();
|
||||
m_vbo2.destroy();
|
||||
doneCurrent();
|
||||
|
||||
// We are done with the current QOpenGLContext, forget it. If there is a
|
||||
// subsequent initialize(), that will then connect to the new context.
|
||||
QObject::disconnect(m_contextWatchConnection);
|
||||
}
|
||||
|
||||
void GLWidget::setScaling(int scale)
|
||||
{
|
||||
if (scale > 30)
|
||||
m_fScale = 1 + qreal(scale - 30) / 30 * 0.25;
|
||||
else if (scale < 30)
|
||||
m_fScale = 1 - (qreal(30 - scale) / 30 * 0.25);
|
||||
else
|
||||
m_fScale = 1;
|
||||
}
|
||||
|
||||
void GLWidget::setLogo()
|
||||
{
|
||||
m_qtLogo = true;
|
||||
}
|
||||
|
||||
void GLWidget::setTexture()
|
||||
{
|
||||
m_qtLogo = false;
|
||||
}
|
||||
|
||||
void GLWidget::setShowBubbles(bool bubbles)
|
||||
{
|
||||
m_showBubbles = bubbles;
|
||||
}
|
||||
|
||||
void GLWidget::paintQtLogo()
|
||||
{
|
||||
m_program1->enableAttributeArray(m_vertexAttr1);
|
||||
m_program1->enableAttributeArray(m_normalAttr1);
|
||||
|
||||
m_vbo1.bind();
|
||||
// The data in the buffer is placed like this:
|
||||
// vertex1.x, vertex1.y, vertex1.z, normal1.x, normal1.y, normal1.z, vertex2.x, ...
|
||||
m_program1->setAttributeBuffer(m_vertexAttr1, GL_FLOAT, 0, 3, 6 * sizeof(GLfloat));
|
||||
m_program1->setAttributeBuffer(m_normalAttr1, GL_FLOAT, 3 * sizeof(GLfloat), 3, 6 * sizeof(GLfloat));
|
||||
m_vbo1.release();
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());
|
||||
|
||||
m_program1->disableAttributeArray(m_normalAttr1);
|
||||
m_program1->disableAttributeArray(m_vertexAttr1);
|
||||
}
|
||||
|
||||
void GLWidget::paintTexturedCube()
|
||||
{
|
||||
m_texture->bind();
|
||||
|
||||
if (!m_vbo2.isCreated()) {
|
||||
static GLfloat afVertices[] = {
|
||||
-0.5, 0.5, 0.5, 0.5,-0.5,0.5,-0.5,-0.5,0.5,
|
||||
0.5, -0.5, 0.5, -0.5,0.5,0.5,0.5,0.5,0.5,
|
||||
-0.5, -0.5, -0.5, 0.5,-0.5,-0.5,-0.5,0.5,-0.5,
|
||||
0.5, 0.5, -0.5, -0.5,0.5,-0.5,0.5,-0.5,-0.5,
|
||||
|
||||
0.5, -0.5, -0.5, 0.5,-0.5,0.5,0.5,0.5,-0.5,
|
||||
0.5, 0.5, 0.5, 0.5,0.5,-0.5,0.5,-0.5,0.5,
|
||||
-0.5, 0.5, -0.5, -0.5,-0.5,0.5,-0.5,-0.5,-0.5,
|
||||
-0.5, -0.5, 0.5, -0.5,0.5,-0.5,-0.5,0.5,0.5,
|
||||
|
||||
0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5,
|
||||
-0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5,
|
||||
-0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5,
|
||||
0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5
|
||||
};
|
||||
|
||||
static GLfloat afTexCoord[] = {
|
||||
0.0f,0.0f, 1.0f,1.0f, 1.0f,0.0f,
|
||||
1.0f,1.0f, 0.0f,0.0f, 0.0f,1.0f,
|
||||
1.0f,1.0f, 1.0f,0.0f, 0.0f,1.0f,
|
||||
0.0f,0.0f, 0.0f,1.0f, 1.0f,0.0f,
|
||||
|
||||
1.0f,1.0f, 1.0f,0.0f, 0.0f,1.0f,
|
||||
0.0f,0.0f, 0.0f,1.0f, 1.0f,0.0f,
|
||||
0.0f,0.0f, 1.0f,1.0f, 1.0f,0.0f,
|
||||
1.0f,1.0f, 0.0f,0.0f, 0.0f,1.0f,
|
||||
|
||||
0.0f,1.0f, 1.0f,0.0f, 1.0f,1.0f,
|
||||
1.0f,0.0f, 0.0f,1.0f, 0.0f,0.0f,
|
||||
1.0f,0.0f, 1.0f,1.0f, 0.0f,0.0f,
|
||||
0.0f,1.0f, 0.0f,0.0f, 1.0f,1.0f
|
||||
};
|
||||
|
||||
GLfloat afNormals[] = {
|
||||
|
||||
0,0,-1, 0,0,-1, 0,0,-1,
|
||||
0,0,-1, 0,0,-1, 0,0,-1,
|
||||
0,0,1, 0,0,1, 0,0,1,
|
||||
0,0,1, 0,0,1, 0,0,1,
|
||||
|
||||
-1,0,0, -1,0,0, -1,0,0,
|
||||
-1,0,0, -1,0,0, -1,0,0,
|
||||
1,0,0, 1,0,0, 1,0,0,
|
||||
1,0,0, 1,0,0, 1,0,0,
|
||||
|
||||
0,-1,0, 0,-1,0, 0,-1,0,
|
||||
0,-1,0, 0,-1,0, 0,-1,0,
|
||||
0,1,0, 0,1,0, 0,1,0,
|
||||
0,1,0, 0,1,0, 0,1,0
|
||||
};
|
||||
|
||||
m_vbo2.create();
|
||||
m_vbo2.bind();
|
||||
m_vbo2.allocate(36 * 8 * sizeof(GLfloat));
|
||||
m_vbo2.write(0, afVertices, sizeof(afVertices));
|
||||
m_vbo2.write(sizeof(afVertices), afTexCoord, sizeof(afTexCoord));
|
||||
m_vbo2.write(sizeof(afVertices) + sizeof(afTexCoord), afNormals, sizeof(afNormals));
|
||||
m_vbo2.release();
|
||||
}
|
||||
|
||||
m_program2->setUniformValue(m_textureUniform2, 0); // use texture unit 0
|
||||
|
||||
m_program2->enableAttributeArray(m_vertexAttr2);
|
||||
m_program2->enableAttributeArray(m_normalAttr2);
|
||||
m_program2->enableAttributeArray(m_texCoordAttr2);
|
||||
|
||||
m_vbo2.bind();
|
||||
// In the buffer we first have 36 vertices (3 floats for each), then 36 texture
|
||||
// coordinates (2 floats for each), then 36 normals (3 floats for each).
|
||||
m_program2->setAttributeBuffer(m_vertexAttr2, GL_FLOAT, 0, 3);
|
||||
m_program2->setAttributeBuffer(m_texCoordAttr2, GL_FLOAT, 36 * 3 * sizeof(GLfloat), 2);
|
||||
m_program2->setAttributeBuffer(m_normalAttr2, GL_FLOAT, 36 * 5 * sizeof(GLfloat), 3);
|
||||
m_vbo2.release();
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||
|
||||
m_program2->disableAttributeArray(m_vertexAttr2);
|
||||
m_program2->disableAttributeArray(m_normalAttr2);
|
||||
m_program2->disableAttributeArray(m_texCoordAttr2);
|
||||
}
|
||||
|
||||
void GLWidget::initializeGL()
|
||||
{
|
||||
initializeOpenGLFunctions();
|
||||
|
||||
m_texture = new QOpenGLTexture(QImage(":/qt.png"));
|
||||
|
||||
m_vshader1 = new QOpenGLShader(QOpenGLShader::Vertex);
|
||||
const char *vsrc1 =
|
||||
"attribute highp vec4 vertex;\n"
|
||||
"attribute mediump vec3 normal;\n"
|
||||
"uniform mediump mat4 matrix;\n"
|
||||
"varying mediump vec4 color;\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" vec3 toLight = normalize(vec3(0.0, 0.3, 1.0));\n"
|
||||
" float angle = max(dot(normal, toLight), 0.0);\n"
|
||||
" vec3 col = vec3(0.40, 1.0, 0.0);\n"
|
||||
" color = vec4(col * 0.2 + col * 0.8 * angle, 1.0);\n"
|
||||
" color = clamp(color, 0.0, 1.0);\n"
|
||||
" gl_Position = matrix * vertex;\n"
|
||||
"}\n";
|
||||
m_vshader1->compileSourceCode(vsrc1);
|
||||
|
||||
m_fshader1 = new QOpenGLShader(QOpenGLShader::Fragment);
|
||||
const char *fsrc1 =
|
||||
"varying mediump vec4 color;\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" gl_FragColor = color;\n"
|
||||
"}\n";
|
||||
m_fshader1->compileSourceCode(fsrc1);
|
||||
|
||||
m_program1 = new QOpenGLShaderProgram;
|
||||
m_program1->addShader(m_vshader1);
|
||||
m_program1->addShader(m_fshader1);
|
||||
m_program1->link();
|
||||
|
||||
m_vertexAttr1 = m_program1->attributeLocation("vertex");
|
||||
m_normalAttr1 = m_program1->attributeLocation("normal");
|
||||
m_matrixUniform1 = m_program1->uniformLocation("matrix");
|
||||
|
||||
m_vshader2 = new QOpenGLShader(QOpenGLShader::Vertex);
|
||||
const char *vsrc2 =
|
||||
"attribute highp vec4 vertex;\n"
|
||||
"attribute highp vec4 texCoord;\n"
|
||||
"attribute mediump vec3 normal;\n"
|
||||
"uniform mediump mat4 matrix;\n"
|
||||
"varying highp vec4 texc;\n"
|
||||
"varying mediump float angle;\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" vec3 toLight = normalize(vec3(0.0, 0.3, 1.0));\n"
|
||||
" angle = max(dot(normal, toLight), 0.0);\n"
|
||||
" gl_Position = matrix * vertex;\n"
|
||||
" texc = texCoord;\n"
|
||||
"}\n";
|
||||
m_vshader2->compileSourceCode(vsrc2);
|
||||
|
||||
m_fshader2 = new QOpenGLShader(QOpenGLShader::Fragment);
|
||||
const char *fsrc2 =
|
||||
"varying highp vec4 texc;\n"
|
||||
"uniform sampler2D tex;\n"
|
||||
"varying mediump float angle;\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" highp vec3 color = texture2D(tex, texc.st).rgb;\n"
|
||||
" color = color * 0.2 + color * 0.8 * angle;\n"
|
||||
" gl_FragColor = vec4(clamp(color, 0.0, 1.0), 1.0);\n"
|
||||
"}\n";
|
||||
m_fshader2->compileSourceCode(fsrc2);
|
||||
|
||||
m_program2 = new QOpenGLShaderProgram;
|
||||
m_program2->addShader(m_vshader2);
|
||||
m_program2->addShader(m_fshader2);
|
||||
m_program2->link();
|
||||
|
||||
m_vertexAttr2 = m_program2->attributeLocation("vertex");
|
||||
m_normalAttr2 = m_program2->attributeLocation("normal");
|
||||
m_texCoordAttr2 = m_program2->attributeLocation("texCoord");
|
||||
m_matrixUniform2 = m_program2->uniformLocation("matrix");
|
||||
m_textureUniform2 = m_program2->uniformLocation("tex");
|
||||
|
||||
m_fAngle = 0;
|
||||
m_fScale = 1;
|
||||
|
||||
createGeometry();
|
||||
|
||||
// Use a vertex buffer object. Client-side pointers are old-school and should be avoided.
|
||||
m_vbo1.create();
|
||||
m_vbo1.bind();
|
||||
// For the cube all the data belonging to the texture coordinates and
|
||||
// normals is placed separately, after the vertices. Here, for the Qt logo,
|
||||
// let's do something different and potentially more efficient: create a
|
||||
// properly interleaved data set.
|
||||
const int vertexCount = m_vertices.count();
|
||||
QList<GLfloat> buf;
|
||||
buf.resize(vertexCount * 3 * 2);
|
||||
GLfloat *p = buf.data();
|
||||
for (int i = 0; i < vertexCount; ++i) {
|
||||
*p++ = m_vertices[i].x();
|
||||
*p++ = m_vertices[i].y();
|
||||
*p++ = m_vertices[i].z();
|
||||
*p++ = m_normals[i].x();
|
||||
*p++ = m_normals[i].y();
|
||||
*p++ = m_normals[i].z();
|
||||
}
|
||||
m_vbo1.allocate(buf.constData(), buf.count() * sizeof(GLfloat));
|
||||
m_vbo1.release();
|
||||
|
||||
createBubbles(bubbleNum - m_bubbles.count());
|
||||
|
||||
// A well-behaved QOpenGLWidget releases OpenGL resources not only upon
|
||||
// destruction, but also when the associated OpenGL context disappears. If
|
||||
// the widget continues to exist, the context's destruction will be
|
||||
// followed by a call to initialize(). This is not strictly mandatory in
|
||||
// widgets that never change their parents.
|
||||
m_contextWatchConnection = QObject::connect(context(), &QOpenGLContext::aboutToBeDestroyed, context(), [this] { reset(); });
|
||||
}
|
||||
|
||||
void GLWidget::paintGL()
|
||||
{
|
||||
createBubbles(bubbleNum - m_bubbles.count());
|
||||
|
||||
QPainter painter;
|
||||
painter.begin(this);
|
||||
|
||||
painter.beginNativePainting();
|
||||
|
||||
glClearColor(m_background.redF(), m_background.greenF(), m_background.blueF(), m_transparent ? 0.0f : 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glFrontFace(GL_CW);
|
||||
glCullFace(GL_FRONT);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
QMatrix4x4 modelview;
|
||||
modelview.rotate(m_fAngle, 0.0f, 1.0f, 0.0f);
|
||||
modelview.rotate(m_fAngle, 1.0f, 0.0f, 0.0f);
|
||||
modelview.rotate(m_fAngle, 0.0f, 0.0f, 1.0f);
|
||||
modelview.scale(m_fScale);
|
||||
modelview.translate(0.0f, -0.2f, 0.0f);
|
||||
|
||||
if (m_qtLogo) {
|
||||
m_program1->bind();
|
||||
m_program1->setUniformValue(m_matrixUniform1, modelview);
|
||||
paintQtLogo();
|
||||
m_program1->release();
|
||||
} else {
|
||||
m_program2->bind();
|
||||
m_program2->setUniformValue(m_matrixUniform2, modelview);
|
||||
paintTexturedCube();
|
||||
m_program2->release();
|
||||
}
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
painter.endNativePainting();
|
||||
|
||||
if (m_showBubbles) {
|
||||
for (Bubble *bubble : std::as_const(m_bubbles))
|
||||
bubble->drawBubble(&painter);
|
||||
}
|
||||
|
||||
if (const int elapsed = m_time.elapsed()) {
|
||||
QString framesPerSecond;
|
||||
framesPerSecond.setNum(m_frames /(elapsed / 1000.0), 'f', 2);
|
||||
painter.setPen(m_transparent ? Qt::black : Qt::white);
|
||||
painter.drawText(20, 40, framesPerSecond + " paintGL calls / s");
|
||||
}
|
||||
|
||||
painter.end();
|
||||
|
||||
for (Bubble *bubble : std::as_const(m_bubbles))
|
||||
bubble->move(rect());
|
||||
|
||||
if (!(m_frames % 100)) {
|
||||
m_time.start();
|
||||
m_frames = 0;
|
||||
}
|
||||
m_fAngle += 1.0f;
|
||||
++m_frames;
|
||||
|
||||
// When requested, follow the ideal way to animate: Rely on
|
||||
// blocking swap and just schedule updates continuously.
|
||||
if (!m_mainWindow || !m_mainWindow->timerEnabled())
|
||||
update();
|
||||
}
|
||||
|
||||
void GLWidget::createBubbles(int number)
|
||||
{
|
||||
for (int i = 0; i < number; ++i) {
|
||||
QPointF position(width()*(0.1 + QRandomGenerator::global()->bounded(0.8)),
|
||||
height()*(0.1 + QRandomGenerator::global()->bounded(0.8)));
|
||||
qreal radius = qMin(width(), height())*(0.0175 + QRandomGenerator::global()->bounded(0.0875));
|
||||
QPointF velocity(width()*0.0175*(-0.5 + QRandomGenerator::global()->bounded(1.0)),
|
||||
height()*0.0175*(-0.5 + QRandomGenerator::global()->bounded(1.0)));
|
||||
|
||||
m_bubbles.append(new Bubble(position, radius, velocity));
|
||||
}
|
||||
}
|
||||
|
||||
void GLWidget::createGeometry()
|
||||
{
|
||||
m_vertices.clear();
|
||||
m_normals.clear();
|
||||
|
||||
qreal x1 = +0.06f;
|
||||
qreal y1 = -0.14f;
|
||||
qreal x2 = +0.14f;
|
||||
qreal y2 = -0.06f;
|
||||
qreal x3 = +0.08f;
|
||||
qreal y3 = +0.00f;
|
||||
qreal x4 = +0.30f;
|
||||
qreal y4 = +0.22f;
|
||||
|
||||
quad(x1, y1, x2, y2, y2, x2, y1, x1);
|
||||
quad(x3, y3, x4, y4, y4, x4, y3, x3);
|
||||
|
||||
extrude(x1, y1, x2, y2);
|
||||
extrude(x2, y2, y2, x2);
|
||||
extrude(y2, x2, y1, x1);
|
||||
extrude(y1, x1, x1, y1);
|
||||
extrude(x3, y3, x4, y4);
|
||||
extrude(x4, y4, y4, x4);
|
||||
extrude(y4, x4, y3, x3);
|
||||
|
||||
const int NumSectors = 100;
|
||||
const qreal sectorAngle = 2 * qreal(M_PI) / NumSectors;
|
||||
|
||||
for (int i = 0; i < NumSectors; ++i) {
|
||||
qreal angle = i * sectorAngle;
|
||||
qreal x5 = 0.30 * sin(angle);
|
||||
qreal y5 = 0.30 * cos(angle);
|
||||
qreal x6 = 0.20 * sin(angle);
|
||||
qreal y6 = 0.20 * cos(angle);
|
||||
|
||||
angle += sectorAngle;
|
||||
qreal x7 = 0.20 * sin(angle);
|
||||
qreal y7 = 0.20 * cos(angle);
|
||||
qreal x8 = 0.30 * sin(angle);
|
||||
qreal y8 = 0.30 * cos(angle);
|
||||
|
||||
quad(x5, y5, x6, y6, x7, y7, x8, y8);
|
||||
|
||||
extrude(x6, y6, x7, y7);
|
||||
extrude(x8, y8, x5, y5);
|
||||
}
|
||||
|
||||
for (int i = 0;i < m_vertices.size();i++)
|
||||
m_vertices[i] *= 2.0f;
|
||||
}
|
||||
|
||||
void GLWidget::quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4)
|
||||
{
|
||||
m_vertices << QVector3D(x1, y1, -0.05f);
|
||||
m_vertices << QVector3D(x2, y2, -0.05f);
|
||||
m_vertices << QVector3D(x4, y4, -0.05f);
|
||||
|
||||
m_vertices << QVector3D(x3, y3, -0.05f);
|
||||
m_vertices << QVector3D(x4, y4, -0.05f);
|
||||
m_vertices << QVector3D(x2, y2, -0.05f);
|
||||
|
||||
QVector3D n = QVector3D::normal
|
||||
(QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(x4 - x1, y4 - y1, 0.0f));
|
||||
|
||||
m_normals << n;
|
||||
m_normals << n;
|
||||
m_normals << n;
|
||||
|
||||
m_normals << n;
|
||||
m_normals << n;
|
||||
m_normals << n;
|
||||
|
||||
m_vertices << QVector3D(x4, y4, 0.05f);
|
||||
m_vertices << QVector3D(x2, y2, 0.05f);
|
||||
m_vertices << QVector3D(x1, y1, 0.05f);
|
||||
|
||||
m_vertices << QVector3D(x2, y2, 0.05f);
|
||||
m_vertices << QVector3D(x4, y4, 0.05f);
|
||||
m_vertices << QVector3D(x3, y3, 0.05f);
|
||||
|
||||
n = QVector3D::normal
|
||||
(QVector3D(x2 - x4, y2 - y4, 0.0f), QVector3D(x1 - x4, y1 - y4, 0.0f));
|
||||
|
||||
m_normals << n;
|
||||
m_normals << n;
|
||||
m_normals << n;
|
||||
|
||||
m_normals << n;
|
||||
m_normals << n;
|
||||
m_normals << n;
|
||||
}
|
||||
|
||||
void GLWidget::extrude(qreal x1, qreal y1, qreal x2, qreal y2)
|
||||
{
|
||||
m_vertices << QVector3D(x1, y1, +0.05f);
|
||||
m_vertices << QVector3D(x2, y2, +0.05f);
|
||||
m_vertices << QVector3D(x1, y1, -0.05f);
|
||||
|
||||
m_vertices << QVector3D(x2, y2, -0.05f);
|
||||
m_vertices << QVector3D(x1, y1, -0.05f);
|
||||
m_vertices << QVector3D(x2, y2, +0.05f);
|
||||
|
||||
QVector3D n = QVector3D::normal
|
||||
(QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(0.0f, 0.0f, -0.1f));
|
||||
|
||||
m_normals << n;
|
||||
m_normals << n;
|
||||
m_normals << n;
|
||||
|
||||
m_normals << n;
|
||||
m_normals << n;
|
||||
m_normals << n;
|
||||
}
|
||||
|
||||
void GLWidget::setTransparent(bool transparent)
|
||||
{
|
||||
setAttribute(Qt::WA_AlwaysStackOnTop, transparent);
|
||||
m_transparent = transparent;
|
||||
// Call update() on the top-level window after toggling AlwayStackOnTop to make sure
|
||||
// the entire backingstore is updated accordingly.
|
||||
window()->update();
|
||||
}
|
||||
|
||||
void GLWidget::resizeGL(int, int)
|
||||
{
|
||||
if (m_mainWindow) {
|
||||
if (!m_btn) {
|
||||
m_btn = new QPushButton("\nAdd widget\n", this);
|
||||
connect(m_btn, &QPushButton::clicked, this, [this] { m_mainWindow->addNew(); });
|
||||
}
|
||||
m_btn->move(20, 80);
|
||||
if (!m_btn2) {
|
||||
m_btn2 = new QPushButton("\nI prefer tabbed widgets\n", this);
|
||||
connect(m_btn2, &QPushButton::clicked, this, [this] { m_mainWindow->showNewWindow(); });
|
||||
}
|
||||
m_btn2->move(20, 160);
|
||||
}
|
||||
}
|
85
tests/manual/examples/opengl/qopenglwidget/glwidget.h
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef GLWIDGET_H
|
||||
#define GLWIDGET_H
|
||||
|
||||
#include <QOpenGLWidget>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLBuffer>
|
||||
#include <QVector3D>
|
||||
#include <QMatrix4x4>
|
||||
#include <QElapsedTimer>
|
||||
#include <QList>
|
||||
#include <QPushButton>
|
||||
|
||||
class Bubble;
|
||||
class MainWindow;
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QOpenGLTexture)
|
||||
QT_FORWARD_DECLARE_CLASS(QOpenGLShader)
|
||||
QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
|
||||
|
||||
class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
GLWidget(MainWindow *maybeMainWindow, const QColor &background);
|
||||
~GLWidget();
|
||||
|
||||
public slots:
|
||||
void setScaling(int scale);
|
||||
void setLogo();
|
||||
void setTexture();
|
||||
void setShowBubbles(bool);
|
||||
void setTransparent(bool transparent);
|
||||
|
||||
protected:
|
||||
void resizeGL(int w, int h) override;
|
||||
void paintGL() override;
|
||||
void initializeGL() override;
|
||||
|
||||
private:
|
||||
void paintTexturedCube();
|
||||
void paintQtLogo();
|
||||
void createGeometry();
|
||||
void createBubbles(int number);
|
||||
void quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4);
|
||||
void extrude(qreal x1, qreal y1, qreal x2, qreal y2);
|
||||
void reset();
|
||||
|
||||
MainWindow *m_mainWindow;
|
||||
qreal m_fAngle = 0;
|
||||
qreal m_fScale = 1;
|
||||
bool m_showBubbles = true;
|
||||
QList<QVector3D> m_vertices;
|
||||
QList<QVector3D> m_normals;
|
||||
bool m_qtLogo = true;
|
||||
QList<Bubble *> m_bubbles;
|
||||
int m_frames = 0;
|
||||
QElapsedTimer m_time;
|
||||
QOpenGLShader *m_vshader1 = nullptr;
|
||||
QOpenGLShader *m_fshader1 = nullptr;
|
||||
QOpenGLShader *m_vshader2 = nullptr;
|
||||
QOpenGLShader *m_fshader2 = nullptr;
|
||||
QOpenGLShaderProgram *m_program1 = nullptr;
|
||||
QOpenGLShaderProgram *m_program2 = nullptr;
|
||||
QOpenGLTexture *m_texture = nullptr;
|
||||
QOpenGLBuffer m_vbo1;
|
||||
QOpenGLBuffer m_vbo2;
|
||||
int m_vertexAttr1 = 0;
|
||||
int m_normalAttr1 = 0;
|
||||
int m_matrixUniform1 = 0;
|
||||
int m_vertexAttr2 = 0;
|
||||
int m_normalAttr2 = 0;
|
||||
int m_texCoordAttr2 = 0;
|
||||
int m_matrixUniform2 = 0;
|
||||
int m_textureUniform2 = 0;
|
||||
bool m_transparent = false;
|
||||
QPushButton *m_btn = nullptr;
|
||||
QPushButton *m_btn2 = nullptr;
|
||||
QColor m_background;
|
||||
QMetaObject::Connection m_contextWatchConnection;
|
||||
};
|
||||
|
||||
#endif
|
42
tests/manual/examples/opengl/qopenglwidget/main.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMainWindow>
|
||||
#include <QColorSpace>
|
||||
#include <QSurfaceFormat>
|
||||
#include <QCommandLineParser>
|
||||
#include <QCommandLineOption>
|
||||
#include "mainwindow.h"
|
||||
|
||||
int main( int argc, char ** argv )
|
||||
{
|
||||
QApplication a( argc, argv );
|
||||
|
||||
QCoreApplication::setApplicationName("Qt QOpenGLWidget Example");
|
||||
QCoreApplication::setOrganizationName("QtProject");
|
||||
QCoreApplication::setApplicationVersion(QT_VERSION_STR);
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(QCoreApplication::applicationName());
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
QCommandLineOption multipleSampleOption("multisample", "Multisampling");
|
||||
parser.addOption(multipleSampleOption);
|
||||
QCommandLineOption srgbOption("srgb", "Use sRGB Color Space");
|
||||
parser.addOption(srgbOption);
|
||||
parser.process(a);
|
||||
|
||||
QSurfaceFormat format;
|
||||
format.setDepthBufferSize(24);
|
||||
format.setStencilBufferSize(8);
|
||||
if (parser.isSet(srgbOption))
|
||||
format.setColorSpace(QColorSpace::SRgb);
|
||||
if (parser.isSet(multipleSampleOption))
|
||||
format.setSamples(4);
|
||||
QSurfaceFormat::setDefaultFormat(format);
|
||||
|
||||
MainWindow mw;
|
||||
mw.resize(1280, 720);
|
||||
mw.show();
|
||||
return a.exec();
|
||||
}
|
188
tests/manual/examples/opengl/qopenglwidget/mainwindow.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMenuBar>
|
||||
#include <QGroupBox>
|
||||
#include <QSlider>
|
||||
#include <QLabel>
|
||||
#include <QCheckBox>
|
||||
#include <QRandomGenerator>
|
||||
#include <QSpinBox>
|
||||
#include <QScrollArea>
|
||||
#include <QTabWidget>
|
||||
#include <QTabBar>
|
||||
#include <QToolButton>
|
||||
|
||||
#include "glwidget.h"
|
||||
|
||||
MainWindow::MainWindow()
|
||||
: m_nextX(1), m_nextY(1)
|
||||
{
|
||||
GLWidget *glwidget = new GLWidget(this, qRgb(20, 20, 50));
|
||||
m_glWidgets << glwidget;
|
||||
QLabel *label = new QLabel(this);
|
||||
m_timer = new QTimer(this);
|
||||
QSlider *slider = new QSlider(this);
|
||||
slider->setOrientation(Qt::Horizontal);
|
||||
|
||||
QLabel *updateLabel = new QLabel("Update interval");
|
||||
QSpinBox *updateInterval = new QSpinBox(this);
|
||||
updateInterval->setSuffix(" ms");
|
||||
updateInterval->setValue(10);
|
||||
updateInterval->setToolTip("Interval for the timer that calls update().\n"
|
||||
"Note that on most systems the swap will block to wait for vsync\n"
|
||||
"and therefore an interval < 16 ms will likely lead to a 60 FPS update rate.");
|
||||
QGroupBox *updateGroupBox = new QGroupBox(this);
|
||||
QCheckBox *timerBased = new QCheckBox("Use timer", this);
|
||||
timerBased->setChecked(false);
|
||||
timerBased->setToolTip("Toggles using a timer to trigger update().\n"
|
||||
"When not set, each paintGL() schedules the next update immediately,\n"
|
||||
"expecting the blocking swap to throttle the thread.\n"
|
||||
"This shows how unnecessary the timer is in most cases.");
|
||||
QCheckBox *transparent = new QCheckBox("Transparent background", this);
|
||||
transparent->setToolTip("Toggles Qt::WA_AlwaysStackOnTop and transparent clear color for glClear().\n"
|
||||
"Note how the button on top stacks incorrectly when enabling this.");
|
||||
QHBoxLayout *updateLayout = new QHBoxLayout;
|
||||
updateLayout->addWidget(updateLabel);
|
||||
updateLayout->addWidget(updateInterval);
|
||||
updateLayout->addWidget(timerBased);
|
||||
updateLayout->addWidget(transparent);
|
||||
updateGroupBox->setLayout(updateLayout);
|
||||
|
||||
slider->setRange(0, 50);
|
||||
slider->setSliderPosition(30);
|
||||
m_timer->setInterval(10);
|
||||
label->setText("A scrollable QOpenGLWidget");
|
||||
label->setAlignment(Qt::AlignHCenter);
|
||||
|
||||
QGroupBox * groupBox = new QGroupBox(this);
|
||||
setCentralWidget(groupBox);
|
||||
groupBox->setTitle("QOpenGLWidget Example");
|
||||
|
||||
m_layout = new QGridLayout(groupBox);
|
||||
|
||||
QScrollArea *scrollArea = new QScrollArea;
|
||||
scrollArea->setWidget(glwidget);
|
||||
|
||||
m_layout->addWidget(scrollArea,1,0,8,1);
|
||||
m_layout->addWidget(label,9,0,1,1);
|
||||
m_layout->addWidget(updateGroupBox, 10, 0, 1, 1);
|
||||
m_layout->addWidget(slider, 11,0,1,1);
|
||||
|
||||
groupBox->setLayout(m_layout);
|
||||
|
||||
|
||||
QMenu *fileMenu = menuBar()->addMenu("&File");
|
||||
fileMenu->addAction("E&xit", this, &QWidget::close);
|
||||
QMenu *showMenu = menuBar()->addMenu("&Show");
|
||||
showMenu->addAction("Show 3D Logo", glwidget, &GLWidget::setLogo);
|
||||
showMenu->addAction("Show 2D Texture", glwidget, &GLWidget::setTexture);
|
||||
QAction *showBubbles = showMenu->addAction("Show bubbles", glwidget, &GLWidget::setShowBubbles);
|
||||
showBubbles->setCheckable(true);
|
||||
showBubbles->setChecked(true);
|
||||
showMenu->addAction("Open tab window", this, &MainWindow::showNewWindow);
|
||||
QMenu *helpMenu = menuBar()->addMenu("&Help");
|
||||
helpMenu->addAction("About Qt", qApp, &QApplication::aboutQt);
|
||||
|
||||
connect(m_timer, &QTimer::timeout, glwidget, QOverload<>::of(&QWidget::update));
|
||||
|
||||
connect(slider, &QAbstractSlider::valueChanged, glwidget, &GLWidget::setScaling);
|
||||
connect(transparent, &QCheckBox::toggled, glwidget, &GLWidget::setTransparent);
|
||||
connect(updateInterval, &QSpinBox::valueChanged,
|
||||
this, &MainWindow::updateIntervalChanged);
|
||||
connect(timerBased, &QCheckBox::toggled, this, &MainWindow::timerUsageChanged);
|
||||
connect(timerBased, &QCheckBox::toggled, updateInterval, &QWidget::setEnabled);
|
||||
|
||||
if (timerBased->isChecked())
|
||||
m_timer->start();
|
||||
else
|
||||
updateInterval->setEnabled(false);
|
||||
}
|
||||
|
||||
void MainWindow::updateIntervalChanged(int value)
|
||||
{
|
||||
m_timer->setInterval(value);
|
||||
if (m_timer->isActive())
|
||||
m_timer->start();
|
||||
}
|
||||
|
||||
void MainWindow::addNew()
|
||||
{
|
||||
if (m_nextY == 4)
|
||||
return;
|
||||
GLWidget *w = new GLWidget(nullptr, qRgb(QRandomGenerator::global()->bounded(256),
|
||||
QRandomGenerator::global()->bounded(256),
|
||||
QRandomGenerator::global()->bounded(256)));
|
||||
m_glWidgets << w;
|
||||
connect(m_timer, &QTimer::timeout, w, QOverload<>::of(&QWidget::update));
|
||||
m_layout->addWidget(w, m_nextY, m_nextX, 1, 1);
|
||||
if (m_nextX == 3) {
|
||||
m_nextX = 1;
|
||||
++m_nextY;
|
||||
} else {
|
||||
++m_nextX;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::timerUsageChanged(bool enabled)
|
||||
{
|
||||
if (enabled) {
|
||||
m_timer->start();
|
||||
} else {
|
||||
m_timer->stop();
|
||||
for (QOpenGLWidget *w : std::as_const(m_glWidgets))
|
||||
w->update();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
m_glWidgets[0]->setMinimumSize(size() + QSize(128, 128));
|
||||
}
|
||||
|
||||
void MainWindow::showNewWindow()
|
||||
{
|
||||
QTabWidget *tabs = new QTabWidget;
|
||||
tabs->resize(800, 600);
|
||||
|
||||
QToolButton *tb = new QToolButton;
|
||||
tb->setText(QLatin1String("+"));
|
||||
tabs->addTab(new QLabel(QLatin1String("Add OpenGL widgets with +")), QString());
|
||||
tabs->setTabEnabled(0, false);
|
||||
tabs->tabBar()->setTabButton(0, QTabBar::RightSide, tb);
|
||||
tabs->tabBar()->setTabsClosable(true);
|
||||
QObject::connect(tabs->tabBar(), &QTabBar::tabCloseRequested, tabs, [tabs](int index) {
|
||||
tabs->widget(index)->deleteLater();
|
||||
});
|
||||
|
||||
const QString msgToTopLevel = QLatin1String("Break out to top-level window");
|
||||
const QString msgFromTopLevel = QLatin1String("Move back under tab widget");
|
||||
|
||||
QObject::connect(tb, &QAbstractButton::clicked, tabs, [=] {
|
||||
GLWidget *glwidget = new GLWidget(nullptr, Qt::blue);
|
||||
glwidget->resize(tabs->size());
|
||||
glwidget->setWindowTitle(QString::asprintf("QOpenGLWidget %p", glwidget));
|
||||
|
||||
QPushButton *btn = new QPushButton(msgToTopLevel, glwidget);
|
||||
connect(btn, &QPushButton::clicked, glwidget, [=] {
|
||||
if (glwidget->parent()) {
|
||||
glwidget->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
glwidget->setParent(nullptr);
|
||||
glwidget->show();
|
||||
btn->setText(msgFromTopLevel);
|
||||
} else {
|
||||
glwidget->setAttribute(Qt::WA_DeleteOnClose, false);
|
||||
tabs->addTab(glwidget, glwidget->windowTitle());
|
||||
btn->setText(msgToTopLevel);
|
||||
}
|
||||
});
|
||||
|
||||
tabs->setCurrentIndex(tabs->addTab(glwidget, glwidget->windowTitle()));
|
||||
});
|
||||
|
||||
tabs->setAttribute(Qt::WA_DeleteOnClose);
|
||||
tabs->show();
|
||||
}
|
39
tests/manual/examples/opengl/qopenglwidget/mainwindow.h
Normal file
@ -0,0 +1,39 @@
|
||||
// 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 <QTimer>
|
||||
#include <QGridLayout>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QOpenGLWidget)
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow();
|
||||
void addNew();
|
||||
bool timerEnabled() const { return m_timer->isActive(); }
|
||||
|
||||
void resizeEvent(QResizeEvent *);
|
||||
|
||||
public slots:
|
||||
void showNewWindow();
|
||||
|
||||
private slots:
|
||||
void updateIntervalChanged(int value);
|
||||
void timerUsageChanged(bool enabled);
|
||||
|
||||
private:
|
||||
QTimer *m_timer;
|
||||
QGridLayout *m_layout;
|
||||
int m_nextX;
|
||||
int m_nextY;
|
||||
QList<QOpenGLWidget *> m_glWidgets;
|
||||
};
|
||||
|
||||
#endif
|
15
tests/manual/examples/opengl/qopenglwidget/qopenglwidget.pro
Normal file
@ -0,0 +1,15 @@
|
||||
QT += widgets opengl openglwidgets
|
||||
|
||||
SOURCES += main.cpp \
|
||||
glwidget.cpp \
|
||||
mainwindow.cpp \
|
||||
bubble.cpp
|
||||
|
||||
HEADERS += glwidget.h \
|
||||
mainwindow.h \
|
||||
bubble.h
|
||||
|
||||
RESOURCES += texture.qrc
|
||||
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/opengl/qopenglwidget
|
||||
INSTALLS += target
|
BIN
tests/manual/examples/opengl/qopenglwidget/qt.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
5
tests/manual/examples/opengl/qopenglwidget/texture.qrc
Normal file
@ -0,0 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>qt.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
8
tests/manual/examples/qpa/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
if(NOT TARGET Qt6::Gui)
|
||||
return()
|
||||
endif()
|
||||
qt_internal_add_example(windows)
|
||||
qt_internal_add_example(qrasterwindow)
|
5
tests/manual/examples/qpa/qpa.pro
Normal file
@ -0,0 +1,5 @@
|
||||
requires(qtHaveModule(gui))
|
||||
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = windows \
|
||||
qrasterwindow
|
35
tests/manual/examples/qpa/qrasterwindow/CMakeLists.txt
Normal file
@ -0,0 +1,35 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(qrasterwindow LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/qpa/qrasterwindow")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(qrasterwindow
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(qrasterwindow PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(qrasterwindow PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
)
|
||||
|
||||
install(TARGETS qrasterwindow
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
91
tests/manual/examples/qpa/qrasterwindow/main.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QRasterWindow>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QGuiApplication>
|
||||
#include <QMatrix4x4>
|
||||
#include <QTimer>
|
||||
|
||||
static QPainterPath painterPathForTriangle()
|
||||
{
|
||||
static const QPointF bottomLeft(-1.0, -1.0);
|
||||
static const QPointF top(0.0, 1.0);
|
||||
static const QPointF bottomRight(1.0, -1.0);
|
||||
|
||||
QPainterPath path(bottomLeft);
|
||||
path.lineTo(top);
|
||||
path.lineTo(bottomRight);
|
||||
path.closeSubpath();
|
||||
return path;
|
||||
}
|
||||
|
||||
class PaintedWindow : public QRasterWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PaintedWindow()
|
||||
{
|
||||
m_view.lookAt(QVector3D(3,1,1),
|
||||
QVector3D(0,0,0),
|
||||
QVector3D(0,1,0));
|
||||
m_timer.setInterval(16);
|
||||
connect(&m_timer, SIGNAL(timeout()), this, SLOT(update()));
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter p(this);
|
||||
p.fillRect(QRect(0,0,width(),height()),Qt::gray);
|
||||
|
||||
p.setWorldTransform(m_window_matrix.toTransform());
|
||||
|
||||
QMatrix4x4 mvp = m_projection * m_view * m_model;
|
||||
p.setTransform(mvp.toTransform(), true);
|
||||
|
||||
p.fillPath(painterPathForTriangle(), m_brush);
|
||||
|
||||
m_model.rotate(1, 0, 1, 0);
|
||||
}
|
||||
|
||||
void resizeEvent(QResizeEvent *)
|
||||
{
|
||||
m_window_matrix = QTransform();
|
||||
m_window_matrix.translate(width() / 2.0, height() / 2.0);
|
||||
m_window_matrix.scale(width() / 2.0, -height() / 2.0);
|
||||
|
||||
m_projection.setToIdentity();
|
||||
m_projection.perspective(45.f, qreal(width()) / qreal(height()), 0.1f, 100.f);
|
||||
|
||||
QLinearGradient gradient(QPointF(-1,-1), QPointF(1,1));
|
||||
gradient.setColorAt(0, Qt::red);
|
||||
gradient.setColorAt(1, Qt::green);
|
||||
|
||||
m_brush = QBrush(gradient);
|
||||
}
|
||||
|
||||
private:
|
||||
QMatrix4x4 m_window_matrix;
|
||||
QMatrix4x4 m_projection;
|
||||
QMatrix4x4 m_view;
|
||||
QMatrix4x4 m_model;
|
||||
QBrush m_brush;
|
||||
QTimer m_timer;
|
||||
};
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
PaintedWindow window;
|
||||
window.create();
|
||||
window.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
#include "main.moc"
|
@ -0,0 +1,4 @@
|
||||
SOURCES += main.cpp
|
||||
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/qpa/qrasterwindow
|
||||
INSTALLS += target
|
38
tests/manual/examples/qpa/windows/CMakeLists.txt
Normal file
@ -0,0 +1,38 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(windows LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/qpa/windows")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(windows
|
||||
main.cpp
|
||||
window.cpp window.h
|
||||
)
|
||||
|
||||
set_target_properties(windows PROPERTIES
|
||||
WIN32_EXECUTABLE FALSE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(windows PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::CorePrivate
|
||||
Qt6::Gui
|
||||
Qt6::GuiPrivate
|
||||
)
|
||||
|
||||
install(TARGETS windows
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
50
tests/manual/examples/qpa/windows/main.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
#include <QRect>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include "window.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
typedef QSharedPointer<QWindow> WindowPtr;
|
||||
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
Window a;
|
||||
a.setFramePosition(QPoint(10, 10));
|
||||
a.setTitle(QStringLiteral("Window A"));
|
||||
a.setObjectName(a.title());
|
||||
a.setVisible(true);
|
||||
|
||||
Window b;
|
||||
b.setFramePosition(QPoint(100, 100));
|
||||
b.setTitle(QStringLiteral("Window B"));
|
||||
b.setObjectName(b.title());
|
||||
b.setVisible(true);
|
||||
|
||||
Window child(&b);
|
||||
child.setObjectName(QStringLiteral("ChildOfB"));
|
||||
child.setVisible(true);
|
||||
|
||||
// create one window on each additional screen as well
|
||||
|
||||
QList<WindowPtr> windows;
|
||||
const QList<QScreen *> screens = app.screens();
|
||||
for (QScreen *screen : screens) {
|
||||
if (screen == app.primaryScreen())
|
||||
continue;
|
||||
WindowPtr window(new Window(screen));
|
||||
QRect geometry = window->geometry();
|
||||
geometry.moveCenter(screen->availableGeometry().center());
|
||||
window->setGeometry(geometry);
|
||||
window->setVisible(true);
|
||||
window->setTitle(screen->name());
|
||||
window->setObjectName(window->title());
|
||||
windows.push_back(window);
|
||||
}
|
||||
return app.exec();
|
||||
}
|
164
tests/manual/examples/qpa/windows/window.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "window.h"
|
||||
|
||||
#include <private/qguiapplication_p.h>
|
||||
|
||||
#include <QBackingStore>
|
||||
#include <QPainter>
|
||||
|
||||
static int colorIndexId = 0;
|
||||
|
||||
QColor colorTable[] =
|
||||
{
|
||||
QColor("#f09f8f"),
|
||||
QColor("#a2bff2"),
|
||||
QColor("#c0ef8f")
|
||||
};
|
||||
|
||||
Window::Window(QScreen *screen)
|
||||
: QWindow(screen)
|
||||
, m_backgroundColorIndex(colorIndexId++)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
Window::Window(QWindow *parent)
|
||||
: QWindow(parent)
|
||||
, m_backgroundColorIndex(colorIndexId++)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
void Window::initialize()
|
||||
{
|
||||
if (parent())
|
||||
setGeometry(QRect(160, 120, 320, 240));
|
||||
else {
|
||||
setFlags(flags() | Qt::WindowTitleHint | Qt::WindowSystemMenuHint
|
||||
| Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
|
||||
const QSize baseSize = QSize(640, 480);
|
||||
setGeometry(QRect(geometry().topLeft(), baseSize));
|
||||
|
||||
setSizeIncrement(QSize(10, 10));
|
||||
setBaseSize(baseSize);
|
||||
setMinimumSize(QSize(240, 160));
|
||||
setMaximumSize(QSize(800, 600));
|
||||
}
|
||||
|
||||
create();
|
||||
m_backingStore = new QBackingStore(this);
|
||||
|
||||
m_image = QImage(geometry().size(), QImage::Format_RGB32);
|
||||
m_image.fill(colorTable[m_backgroundColorIndex % (sizeof(colorTable) / sizeof(colorTable[0]))].rgba());
|
||||
|
||||
m_lastPos = QPoint(-1, -1);
|
||||
m_renderTimer = 0;
|
||||
}
|
||||
|
||||
void Window::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
m_lastPos = event->position().toPoint();
|
||||
}
|
||||
|
||||
void Window::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (m_lastPos != QPoint(-1, -1)) {
|
||||
QPainter p(&m_image);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
p.drawLine(m_lastPos, event->position().toPoint());
|
||||
m_lastPos = event->position().toPoint();
|
||||
|
||||
scheduleRender();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if (m_lastPos != QPoint(-1, -1)) {
|
||||
QPainter p(&m_image);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
p.drawLine(m_lastPos, event->position().toPoint());
|
||||
m_lastPos = QPoint(-1, -1);
|
||||
|
||||
scheduleRender();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::exposeEvent(QExposeEvent *)
|
||||
{
|
||||
scheduleRender();
|
||||
}
|
||||
|
||||
void Window::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
QImage old = m_image;
|
||||
|
||||
int width = qMax(geometry().width(), old.width());
|
||||
int height = qMax(geometry().height(), old.height());
|
||||
|
||||
if (width > old.width() || height > old.height()) {
|
||||
m_image = QImage(width, height, QImage::Format_RGB32);
|
||||
m_image.fill(colorTable[(m_backgroundColorIndex) % (sizeof(colorTable) / sizeof(colorTable[0]))].rgba());
|
||||
|
||||
QPainter p(&m_image);
|
||||
p.drawImage(0, 0, old);
|
||||
}
|
||||
scheduleRender();
|
||||
}
|
||||
|
||||
void Window::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Backspace:
|
||||
m_text.chop(1);
|
||||
break;
|
||||
case Qt::Key_Enter:
|
||||
case Qt::Key_Return:
|
||||
m_text.append('\n');
|
||||
break;
|
||||
default:
|
||||
m_text.append(event->text());
|
||||
break;
|
||||
}
|
||||
scheduleRender();
|
||||
}
|
||||
|
||||
void Window::scheduleRender()
|
||||
{
|
||||
if (!m_renderTimer)
|
||||
m_renderTimer = startTimer(1);
|
||||
}
|
||||
|
||||
void Window::timerEvent(QTimerEvent *)
|
||||
{
|
||||
if (isExposed())
|
||||
render();
|
||||
killTimer(m_renderTimer);
|
||||
m_renderTimer = 0;
|
||||
}
|
||||
|
||||
void Window::render()
|
||||
{
|
||||
QRect rect(QPoint(), geometry().size());
|
||||
m_backingStore->resize(rect.size());
|
||||
|
||||
m_backingStore->beginPaint(rect);
|
||||
|
||||
QPaintDevice *device = m_backingStore->paintDevice();
|
||||
|
||||
QPainter p(device);
|
||||
p.drawImage(0, 0, m_image);
|
||||
|
||||
QFont font;
|
||||
font.setPixelSize(32);
|
||||
|
||||
p.setFont(font);
|
||||
p.drawText(rect, 0, m_text);
|
||||
|
||||
m_backingStore->endPaint();
|
||||
m_backingStore->flush(rect);
|
||||
}
|
||||
|
||||
|
41
tests/manual/examples/qpa/windows/window.h
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef WINDOW_H
|
||||
#define WINDOW_H
|
||||
|
||||
#include <QWindow>
|
||||
#include <QImage>
|
||||
|
||||
class Window : public QWindow
|
||||
{
|
||||
public:
|
||||
Window(QWindow *parent = nullptr);
|
||||
Window(QScreen *screen);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *) override;
|
||||
void mouseMoveEvent(QMouseEvent *) override;
|
||||
void mouseReleaseEvent(QMouseEvent *) override;
|
||||
|
||||
void keyPressEvent(QKeyEvent *) override;
|
||||
|
||||
void exposeEvent(QExposeEvent *) override;
|
||||
void resizeEvent(QResizeEvent *) override;
|
||||
|
||||
void timerEvent(QTimerEvent *) override;
|
||||
|
||||
private:
|
||||
void render();
|
||||
void scheduleRender();
|
||||
void initialize();
|
||||
|
||||
QString m_text;
|
||||
QImage m_image;
|
||||
QPoint m_lastPos;
|
||||
int m_backgroundColorIndex;
|
||||
QBackingStore *m_backingStore;
|
||||
int m_renderTimer;
|
||||
};
|
||||
|
||||
#endif // WINDOW_H
|
9
tests/manual/examples/qpa/windows/windows.pro
Normal file
@ -0,0 +1,9 @@
|
||||
CONFIG += console
|
||||
QT += gui-private core-private
|
||||
|
||||
HEADERS += window.h
|
||||
SOURCES += window.cpp main.cpp
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/qpa/windows
|
||||
INSTALLS += target
|
54
tests/manual/examples/widgets/application/CMakeLists.txt
Normal 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(application LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/mainwindows/application")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(application
|
||||
main.cpp
|
||||
mainwindow.cpp mainwindow.h
|
||||
)
|
||||
|
||||
set_target_properties(application PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(application PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(application_resource_files
|
||||
"images/copy.png"
|
||||
"images/cut.png"
|
||||
"images/new.png"
|
||||
"images/open.png"
|
||||
"images/paste.png"
|
||||
"images/save.png"
|
||||
)
|
||||
|
||||
qt_add_resources(application "application"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
${application_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS application
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
13
tests/manual/examples/widgets/application/application.pro
Normal file
@ -0,0 +1,13 @@
|
||||
QT += widgets
|
||||
requires(qtConfig(filedialog))
|
||||
|
||||
HEADERS = mainwindow.h
|
||||
SOURCES = main.cpp \
|
||||
mainwindow.cpp
|
||||
#! [0]
|
||||
RESOURCES = application.qrc
|
||||
#! [0]
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/mainwindows/application
|
||||
INSTALLS += target
|
10
tests/manual/examples/widgets/application/application.qrc
Normal 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>
|
BIN
tests/manual/examples/widgets/application/images/copy.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
tests/manual/examples/widgets/application/images/cut.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
tests/manual/examples/widgets/application/images/new.png
Normal file
After Width: | Height: | Size: 852 B |
BIN
tests/manual/examples/widgets/application/images/open.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
tests/manual/examples/widgets/application/images/paste.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
tests/manual/examples/widgets/application/images/save.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
28
tests/manual/examples/widgets/application/main.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
// 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::setOrganizationName("QtProject");
|
||||
QCoreApplication::setApplicationName("Application Example");
|
||||
QCoreApplication::setApplicationVersion(QT_VERSION_STR);
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(QCoreApplication::applicationName());
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
parser.addPositionalArgument("file", "The file to open.");
|
||||
parser.process(app);
|
||||
|
||||
MainWindow mainWin;
|
||||
if (!parser.positionalArguments().isEmpty())
|
||||
mainWin.loadFile(parser.positionalArguments().first());
|
||||
mainWin.show();
|
||||
return app.exec();
|
||||
}
|
306
tests/manual/examples/widgets/application/mainwindow.cpp
Normal file
@ -0,0 +1,306 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
MainWindow::MainWindow()
|
||||
: textEdit(new QPlainTextEdit)
|
||||
{
|
||||
setCentralWidget(textEdit);
|
||||
|
||||
createActions();
|
||||
createStatusBar();
|
||||
|
||||
readSettings();
|
||||
|
||||
connect(textEdit->document(), &QTextDocument::contentsChanged,
|
||||
this, &MainWindow::documentWasModified);
|
||||
|
||||
#ifndef QT_NO_SESSIONMANAGER
|
||||
connect(qApp, &QGuiApplication::commitDataRequest,
|
||||
this, &MainWindow::commitData);
|
||||
#endif
|
||||
|
||||
setCurrentFile(QString());
|
||||
setUnifiedTitleAndToolBarOnMac(true);
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
if (maybeSave()) {
|
||||
writeSettings();
|
||||
event->accept();
|
||||
} else {
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::newFile()
|
||||
{
|
||||
if (maybeSave()) {
|
||||
textEdit->clear();
|
||||
setCurrentFile(QString());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::open()
|
||||
{
|
||||
if (maybeSave()) {
|
||||
QString fileName = QFileDialog::getOpenFileName(this);
|
||||
if (!fileName.isEmpty())
|
||||
loadFile(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
bool MainWindow::save()
|
||||
{
|
||||
if (curFile.isEmpty()) {
|
||||
return saveAs();
|
||||
} else {
|
||||
return saveFile(curFile);
|
||||
}
|
||||
}
|
||||
|
||||
bool MainWindow::saveAs()
|
||||
{
|
||||
QFileDialog dialog(this);
|
||||
dialog.setWindowModality(Qt::WindowModal);
|
||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
if (dialog.exec() != QDialog::Accepted)
|
||||
return false;
|
||||
return saveFile(dialog.selectedFiles().first());
|
||||
}
|
||||
|
||||
void MainWindow::about()
|
||||
{
|
||||
QMessageBox::about(this, tr("About Application"),
|
||||
tr("The <b>Application</b> example demonstrates how to "
|
||||
"write modern GUI applications using Qt, with a menu bar, "
|
||||
"toolbars, and a status bar."));
|
||||
}
|
||||
|
||||
void MainWindow::documentWasModified()
|
||||
{
|
||||
setWindowModified(textEdit->document()->isModified());
|
||||
}
|
||||
|
||||
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 *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);
|
||||
|
||||
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);
|
||||
|
||||
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 document to disk"));
|
||||
connect(saveAct, &QAction::triggered, this, &MainWindow::save);
|
||||
fileMenu->addAction(saveAct);
|
||||
fileToolBar->addAction(saveAct);
|
||||
|
||||
const QIcon saveAsIcon = QIcon::fromTheme("document-save-as");
|
||||
QAction *saveAsAct = fileMenu->addAction(saveAsIcon, tr("Save &As..."), this, &MainWindow::saveAs);
|
||||
saveAsAct->setShortcuts(QKeySequence::SaveAs);
|
||||
saveAsAct->setStatusTip(tr("Save the document under a new name"));
|
||||
|
||||
fileMenu->addSeparator();
|
||||
|
||||
const QIcon exitIcon = QIcon::fromTheme("application-exit");
|
||||
QAction *exitAct = fileMenu->addAction(exitIcon, tr("E&xit"), this, &QWidget::close);
|
||||
exitAct->setShortcuts(QKeySequence::Quit);
|
||||
exitAct->setStatusTip(tr("Exit the application"));
|
||||
|
||||
QMenu *editMenu = menuBar()->addMenu(tr("&Edit"));
|
||||
QToolBar *editToolBar = addToolBar(tr("Edit"));
|
||||
|
||||
#ifndef QT_NO_CLIPBOARD
|
||||
const QIcon cutIcon = QIcon::fromTheme("edit-cut", QIcon(":/images/cut.png"));
|
||||
QAction *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, textEdit, &QPlainTextEdit::cut);
|
||||
editMenu->addAction(cutAct);
|
||||
editToolBar->addAction(cutAct);
|
||||
|
||||
const QIcon copyIcon = QIcon::fromTheme("edit-copy", QIcon(":/images/copy.png"));
|
||||
QAction *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, textEdit, &QPlainTextEdit::copy);
|
||||
editMenu->addAction(copyAct);
|
||||
editToolBar->addAction(copyAct);
|
||||
|
||||
const QIcon pasteIcon = QIcon::fromTheme("edit-paste", QIcon(":/images/paste.png"));
|
||||
QAction *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, textEdit, &QPlainTextEdit::paste);
|
||||
editMenu->addAction(pasteAct);
|
||||
editToolBar->addAction(pasteAct);
|
||||
|
||||
menuBar()->addSeparator();
|
||||
|
||||
#endif // !QT_NO_CLIPBOARD
|
||||
|
||||
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"));
|
||||
|
||||
#ifndef QT_NO_CLIPBOARD
|
||||
cutAct->setEnabled(false);
|
||||
copyAct->setEnabled(false);
|
||||
connect(textEdit, &QPlainTextEdit::copyAvailable, cutAct, &QAction::setEnabled);
|
||||
connect(textEdit, &QPlainTextEdit::copyAvailable, copyAct, &QAction::setEnabled);
|
||||
#endif // !QT_NO_CLIPBOARD
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
bool MainWindow::maybeSave()
|
||||
{
|
||||
if (!textEdit->document()->isModified())
|
||||
return true;
|
||||
const QMessageBox::StandardButton ret
|
||||
= QMessageBox::warning(this, tr("Application"),
|
||||
tr("The document has been modified.\n"
|
||||
"Do you want to save your changes?"),
|
||||
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
||||
switch (ret) {
|
||||
case QMessageBox::Save:
|
||||
return save();
|
||||
case QMessageBox::Cancel:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::loadFile(const QString &fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
||||
QMessageBox::warning(this, tr("Application"),
|
||||
tr("Cannot read file %1:\n%2.")
|
||||
.arg(QDir::toNativeSeparators(fileName), file.errorString()));
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream in(&file);
|
||||
#ifndef QT_NO_CURSOR
|
||||
QGuiApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
#endif
|
||||
textEdit->setPlainText(in.readAll());
|
||||
#ifndef QT_NO_CURSOR
|
||||
QGuiApplication::restoreOverrideCursor();
|
||||
#endif
|
||||
|
||||
setCurrentFile(fileName);
|
||||
statusBar()->showMessage(tr("File loaded"), 2000);
|
||||
}
|
||||
|
||||
bool MainWindow::saveFile(const QString &fileName)
|
||||
{
|
||||
QString errorMessage;
|
||||
|
||||
QGuiApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
QSaveFile file(fileName);
|
||||
if (file.open(QFile::WriteOnly | QFile::Text)) {
|
||||
QTextStream out(&file);
|
||||
out << textEdit->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("Application"), errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
setCurrentFile(fileName);
|
||||
statusBar()->showMessage(tr("File saved"), 2000);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::setCurrentFile(const QString &fileName)
|
||||
{
|
||||
curFile = fileName;
|
||||
textEdit->document()->setModified(false);
|
||||
setWindowModified(false);
|
||||
|
||||
QString shownName = curFile;
|
||||
if (curFile.isEmpty())
|
||||
shownName = "untitled.txt";
|
||||
setWindowFilePath(shownName);
|
||||
}
|
||||
|
||||
QString MainWindow::strippedName(const QString &fullFileName)
|
||||
{
|
||||
return QFileInfo(fullFileName).fileName();
|
||||
}
|
||||
|
||||
#ifndef QT_NO_SESSIONMANAGER
|
||||
void MainWindow::commitData(QSessionManager &manager)
|
||||
{
|
||||
if (manager.allowsInteraction()) {
|
||||
if (!maybeSave())
|
||||
manager.cancel();
|
||||
} else {
|
||||
// Non-interactive: save without asking
|
||||
if (textEdit->document()->isModified())
|
||||
save();
|
||||
}
|
||||
}
|
||||
#endif
|
53
tests/manual/examples/widgets/application/mainwindow.h
Normal file
@ -0,0 +1,53 @@
|
||||
// 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 QMenu;
|
||||
class QPlainTextEdit;
|
||||
class QSessionManager;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow();
|
||||
|
||||
void loadFile(const QString &fileName);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void newFile();
|
||||
void open();
|
||||
bool save();
|
||||
bool saveAs();
|
||||
void about();
|
||||
void documentWasModified();
|
||||
#ifndef QT_NO_SESSIONMANAGER
|
||||
void commitData(QSessionManager &);
|
||||
#endif
|
||||
|
||||
private:
|
||||
void createActions();
|
||||
void createStatusBar();
|
||||
void readSettings();
|
||||
void writeSettings();
|
||||
bool maybeSave();
|
||||
bool saveFile(const QString &fileName);
|
||||
void setCurrentFile(const QString &fileName);
|
||||
QString strippedName(const QString &fullFileName);
|
||||
|
||||
QPlainTextEdit *textEdit;
|
||||
QString curFile;
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,55 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(classwizard LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/dialogs/classwizard")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(classwizard
|
||||
classwizard.cpp classwizard.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(classwizard PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(classwizard PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(classwizard_resource_files
|
||||
"images/background.png"
|
||||
"images/banner.png"
|
||||
"images/logo1.png"
|
||||
"images/logo2.png"
|
||||
"images/logo3.png"
|
||||
"images/watermark1.png"
|
||||
"images/watermark2.png"
|
||||
)
|
||||
|
||||
qt_add_resources(classwizard "classwizard"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
${classwizard_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS classwizard
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
@ -0,0 +1,394 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#include "classwizard.h"
|
||||
|
||||
//! [0] //! [1]
|
||||
ClassWizard::ClassWizard(QWidget *parent)
|
||||
: QWizard(parent)
|
||||
{
|
||||
addPage(new IntroPage);
|
||||
addPage(new ClassInfoPage);
|
||||
addPage(new CodeStylePage);
|
||||
addPage(new OutputFilesPage);
|
||||
addPage(new ConclusionPage);
|
||||
//! [0]
|
||||
|
||||
setPixmap(QWizard::BannerPixmap, QPixmap(":/images/banner.png"));
|
||||
setPixmap(QWizard::BackgroundPixmap, QPixmap(":/images/background.png"));
|
||||
|
||||
setWindowTitle(tr("Class Wizard"));
|
||||
//! [2]
|
||||
}
|
||||
//! [1] //! [2]
|
||||
|
||||
//! [3]
|
||||
void ClassWizard::accept()
|
||||
//! [3] //! [4]
|
||||
{
|
||||
QByteArray className = field("className").toByteArray();
|
||||
QByteArray baseClass = field("baseClass").toByteArray();
|
||||
QByteArray macroName = field("macroName").toByteArray();
|
||||
QByteArray baseInclude = field("baseInclude").toByteArray();
|
||||
|
||||
QString outputDir = field("outputDir").toString();
|
||||
QString header = field("header").toString();
|
||||
QString implementation = field("implementation").toString();
|
||||
//! [4]
|
||||
|
||||
QByteArray block;
|
||||
|
||||
if (field("comment").toBool()) {
|
||||
block += "/*\n";
|
||||
block += " " + header.toLatin1() + '\n';
|
||||
block += "*/\n";
|
||||
block += '\n';
|
||||
}
|
||||
if (field("protect").toBool()) {
|
||||
block += "#ifndef " + macroName + '\n';
|
||||
block += "#define " + macroName + '\n';
|
||||
block += '\n';
|
||||
}
|
||||
if (field("includeBase").toBool()) {
|
||||
block += "#include " + baseInclude + '\n';
|
||||
block += '\n';
|
||||
}
|
||||
|
||||
block += "class " + className;
|
||||
if (!baseClass.isEmpty())
|
||||
block += " : public " + baseClass;
|
||||
block += '\n';
|
||||
block += "{\n";
|
||||
|
||||
/* qmake ignore Q_OBJECT */
|
||||
|
||||
if (field("qobjectMacro").toBool()) {
|
||||
block += " Q_OBJECT\n";
|
||||
block += '\n';
|
||||
}
|
||||
block += "public:\n";
|
||||
|
||||
if (field("qobjectCtor").toBool()) {
|
||||
block += " " + className + "(QObject *parent = nullptr);\n";
|
||||
} else if (field("qwidgetCtor").toBool()) {
|
||||
block += " " + className + "(QWidget *parent = nullptr);\n";
|
||||
} else if (field("defaultCtor").toBool()) {
|
||||
block += " " + className + "();\n";
|
||||
if (field("copyCtor").toBool()) {
|
||||
block += " " + className + "(const " + className + " &other);\n";
|
||||
block += '\n';
|
||||
block += " " + className + " &operator=" + "(const " + className
|
||||
+ " &other);\n";
|
||||
}
|
||||
}
|
||||
block += "};\n";
|
||||
|
||||
if (field("protect").toBool()) {
|
||||
block += '\n';
|
||||
block += "#endif\n";
|
||||
}
|
||||
|
||||
QFile headerFile(outputDir + '/' + header);
|
||||
if (!headerFile.open(QFile::WriteOnly | QFile::Text)) {
|
||||
QMessageBox::warning(nullptr, QObject::tr("Simple Wizard"),
|
||||
QObject::tr("Cannot write file %1:\n%2")
|
||||
.arg(headerFile.fileName())
|
||||
.arg(headerFile.errorString()));
|
||||
return;
|
||||
}
|
||||
headerFile.write(block);
|
||||
|
||||
block.clear();
|
||||
|
||||
if (field("comment").toBool()) {
|
||||
block += "/*\n";
|
||||
block += " " + implementation.toLatin1() + '\n';
|
||||
block += "*/\n";
|
||||
block += '\n';
|
||||
}
|
||||
block += "#include \"" + header.toLatin1() + "\"\n";
|
||||
block += '\n';
|
||||
|
||||
if (field("qobjectCtor").toBool()) {
|
||||
block += className + "::" + className + "(QObject *parent)\n";
|
||||
block += " : " + baseClass + "(parent)\n";
|
||||
block += "{\n";
|
||||
block += "}\n";
|
||||
} else if (field("qwidgetCtor").toBool()) {
|
||||
block += className + "::" + className + "(QWidget *parent)\n";
|
||||
block += " : " + baseClass + "(parent)\n";
|
||||
block += "{\n";
|
||||
block += "}\n";
|
||||
} else if (field("defaultCtor").toBool()) {
|
||||
block += className + "::" + className + "()\n";
|
||||
block += "{\n";
|
||||
block += " // missing code\n";
|
||||
block += "}\n";
|
||||
|
||||
if (field("copyCtor").toBool()) {
|
||||
block += "\n";
|
||||
block += className + "::" + className + "(const " + className
|
||||
+ " &other)\n";
|
||||
block += "{\n";
|
||||
block += " *this = other;\n";
|
||||
block += "}\n";
|
||||
block += '\n';
|
||||
block += className + " &" + className + "::operator=(const "
|
||||
+ className + " &other)\n";
|
||||
block += "{\n";
|
||||
if (!baseClass.isEmpty())
|
||||
block += " " + baseClass + "::operator=(other);\n";
|
||||
block += " // missing code\n";
|
||||
block += " return *this;\n";
|
||||
block += "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
QFile implementationFile(outputDir + '/' + implementation);
|
||||
if (!implementationFile.open(QFile::WriteOnly | QFile::Text)) {
|
||||
QMessageBox::warning(nullptr, QObject::tr("Simple Wizard"),
|
||||
QObject::tr("Cannot write file %1:\n%2")
|
||||
.arg(implementationFile.fileName())
|
||||
.arg(implementationFile.errorString()));
|
||||
return;
|
||||
}
|
||||
implementationFile.write(block);
|
||||
|
||||
//! [5]
|
||||
QDialog::accept();
|
||||
//! [5] //! [6]
|
||||
}
|
||||
//! [6]
|
||||
|
||||
//! [7]
|
||||
IntroPage::IntroPage(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
setTitle(tr("Introduction"));
|
||||
setPixmap(QWizard::WatermarkPixmap, QPixmap(":/images/watermark1.png"));
|
||||
|
||||
label = new QLabel(tr("This wizard will generate a skeleton C++ class "
|
||||
"definition, including a few functions. You simply "
|
||||
"need to specify the class name and set a few "
|
||||
"options to produce a header file and an "
|
||||
"implementation file for your new C++ class."));
|
||||
label->setWordWrap(true);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
layout->addWidget(label);
|
||||
setLayout(layout);
|
||||
}
|
||||
//! [7]
|
||||
|
||||
//! [8] //! [9]
|
||||
ClassInfoPage::ClassInfoPage(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
//! [8]
|
||||
setTitle(tr("Class Information"));
|
||||
setSubTitle(tr("Specify basic information about the class for which you "
|
||||
"want to generate skeleton source code files."));
|
||||
setPixmap(QWizard::LogoPixmap, QPixmap(":/images/logo1.png"));
|
||||
|
||||
//! [10]
|
||||
classNameLabel = new QLabel(tr("&Class name:"));
|
||||
classNameLineEdit = new QLineEdit;
|
||||
classNameLabel->setBuddy(classNameLineEdit);
|
||||
|
||||
baseClassLabel = new QLabel(tr("B&ase class:"));
|
||||
baseClassLineEdit = new QLineEdit;
|
||||
baseClassLabel->setBuddy(baseClassLineEdit);
|
||||
|
||||
qobjectMacroCheckBox = new QCheckBox(tr("Generate Q_OBJECT ¯o"));
|
||||
|
||||
//! [10]
|
||||
groupBox = new QGroupBox(tr("C&onstructor"));
|
||||
//! [9]
|
||||
|
||||
qobjectCtorRadioButton = new QRadioButton(tr("&QObject-style constructor"));
|
||||
qwidgetCtorRadioButton = new QRadioButton(tr("Q&Widget-style constructor"));
|
||||
defaultCtorRadioButton = new QRadioButton(tr("&Default constructor"));
|
||||
copyCtorCheckBox = new QCheckBox(tr("&Generate copy constructor and "
|
||||
"operator="));
|
||||
|
||||
defaultCtorRadioButton->setChecked(true);
|
||||
|
||||
connect(defaultCtorRadioButton, &QAbstractButton::toggled,
|
||||
copyCtorCheckBox, &QWidget::setEnabled);
|
||||
|
||||
//! [11] //! [12]
|
||||
registerField("className*", classNameLineEdit);
|
||||
registerField("baseClass", baseClassLineEdit);
|
||||
registerField("qobjectMacro", qobjectMacroCheckBox);
|
||||
//! [11]
|
||||
registerField("qobjectCtor", qobjectCtorRadioButton);
|
||||
registerField("qwidgetCtor", qwidgetCtorRadioButton);
|
||||
registerField("defaultCtor", defaultCtorRadioButton);
|
||||
registerField("copyCtor", copyCtorCheckBox);
|
||||
|
||||
QVBoxLayout *groupBoxLayout = new QVBoxLayout;
|
||||
//! [12]
|
||||
groupBoxLayout->addWidget(qobjectCtorRadioButton);
|
||||
groupBoxLayout->addWidget(qwidgetCtorRadioButton);
|
||||
groupBoxLayout->addWidget(defaultCtorRadioButton);
|
||||
groupBoxLayout->addWidget(copyCtorCheckBox);
|
||||
groupBox->setLayout(groupBoxLayout);
|
||||
|
||||
QGridLayout *layout = new QGridLayout;
|
||||
layout->addWidget(classNameLabel, 0, 0);
|
||||
layout->addWidget(classNameLineEdit, 0, 1);
|
||||
layout->addWidget(baseClassLabel, 1, 0);
|
||||
layout->addWidget(baseClassLineEdit, 1, 1);
|
||||
layout->addWidget(qobjectMacroCheckBox, 2, 0, 1, 2);
|
||||
layout->addWidget(groupBox, 3, 0, 1, 2);
|
||||
setLayout(layout);
|
||||
//! [13]
|
||||
}
|
||||
//! [13]
|
||||
|
||||
//! [14]
|
||||
CodeStylePage::CodeStylePage(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
setTitle(tr("Code Style Options"));
|
||||
setSubTitle(tr("Choose the formatting of the generated code."));
|
||||
setPixmap(QWizard::LogoPixmap, QPixmap(":/images/logo2.png"));
|
||||
|
||||
commentCheckBox = new QCheckBox(tr("&Start generated files with a "
|
||||
//! [14]
|
||||
"comment"));
|
||||
commentCheckBox->setChecked(true);
|
||||
|
||||
protectCheckBox = new QCheckBox(tr("&Protect header file against multiple "
|
||||
"inclusions"));
|
||||
protectCheckBox->setChecked(true);
|
||||
|
||||
macroNameLabel = new QLabel(tr("&Macro name:"));
|
||||
macroNameLineEdit = new QLineEdit;
|
||||
macroNameLabel->setBuddy(macroNameLineEdit);
|
||||
|
||||
includeBaseCheckBox = new QCheckBox(tr("&Include base class definition"));
|
||||
baseIncludeLabel = new QLabel(tr("Base class include:"));
|
||||
baseIncludeLineEdit = new QLineEdit;
|
||||
baseIncludeLabel->setBuddy(baseIncludeLineEdit);
|
||||
|
||||
connect(protectCheckBox, &QAbstractButton::toggled,
|
||||
macroNameLabel, &QWidget::setEnabled);
|
||||
connect(protectCheckBox, &QAbstractButton::toggled,
|
||||
macroNameLineEdit, &QWidget::setEnabled);
|
||||
connect(includeBaseCheckBox, &QAbstractButton::toggled,
|
||||
baseIncludeLabel, &QWidget::setEnabled);
|
||||
connect(includeBaseCheckBox, &QAbstractButton::toggled,
|
||||
baseIncludeLineEdit, &QWidget::setEnabled);
|
||||
|
||||
registerField("comment", commentCheckBox);
|
||||
registerField("protect", protectCheckBox);
|
||||
registerField("macroName", macroNameLineEdit);
|
||||
registerField("includeBase", includeBaseCheckBox);
|
||||
registerField("baseInclude", baseIncludeLineEdit);
|
||||
|
||||
QGridLayout *layout = new QGridLayout;
|
||||
layout->setColumnMinimumWidth(0, 20);
|
||||
layout->addWidget(commentCheckBox, 0, 0, 1, 3);
|
||||
layout->addWidget(protectCheckBox, 1, 0, 1, 3);
|
||||
layout->addWidget(macroNameLabel, 2, 1);
|
||||
layout->addWidget(macroNameLineEdit, 2, 2);
|
||||
layout->addWidget(includeBaseCheckBox, 3, 0, 1, 3);
|
||||
layout->addWidget(baseIncludeLabel, 4, 1);
|
||||
layout->addWidget(baseIncludeLineEdit, 4, 2);
|
||||
//! [15]
|
||||
setLayout(layout);
|
||||
}
|
||||
//! [15]
|
||||
|
||||
//! [16]
|
||||
void CodeStylePage::initializePage()
|
||||
{
|
||||
QString className = field("className").toString();
|
||||
macroNameLineEdit->setText(className.toUpper() + "_H");
|
||||
|
||||
QString baseClass = field("baseClass").toString();
|
||||
|
||||
includeBaseCheckBox->setChecked(!baseClass.isEmpty());
|
||||
includeBaseCheckBox->setEnabled(!baseClass.isEmpty());
|
||||
baseIncludeLabel->setEnabled(!baseClass.isEmpty());
|
||||
baseIncludeLineEdit->setEnabled(!baseClass.isEmpty());
|
||||
|
||||
QRegularExpression rx("Q[A-Z].*");
|
||||
if (baseClass.isEmpty()) {
|
||||
baseIncludeLineEdit->clear();
|
||||
} else if (rx.match(baseClass).hasMatch()) {
|
||||
baseIncludeLineEdit->setText('<' + baseClass + '>');
|
||||
} else {
|
||||
baseIncludeLineEdit->setText('"' + baseClass.toLower() + ".h\"");
|
||||
}
|
||||
}
|
||||
//! [16]
|
||||
|
||||
OutputFilesPage::OutputFilesPage(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
setTitle(tr("Output Files"));
|
||||
setSubTitle(tr("Specify where you want the wizard to put the generated "
|
||||
"skeleton code."));
|
||||
setPixmap(QWizard::LogoPixmap, QPixmap(":/images/logo3.png"));
|
||||
|
||||
outputDirLabel = new QLabel(tr("&Output directory:"));
|
||||
outputDirLineEdit = new QLineEdit;
|
||||
outputDirLabel->setBuddy(outputDirLineEdit);
|
||||
|
||||
headerLabel = new QLabel(tr("&Header file name:"));
|
||||
headerLineEdit = new QLineEdit;
|
||||
headerLabel->setBuddy(headerLineEdit);
|
||||
|
||||
implementationLabel = new QLabel(tr("&Implementation file name:"));
|
||||
implementationLineEdit = new QLineEdit;
|
||||
implementationLabel->setBuddy(implementationLineEdit);
|
||||
|
||||
registerField("outputDir*", outputDirLineEdit);
|
||||
registerField("header*", headerLineEdit);
|
||||
registerField("implementation*", implementationLineEdit);
|
||||
|
||||
QGridLayout *layout = new QGridLayout;
|
||||
layout->addWidget(outputDirLabel, 0, 0);
|
||||
layout->addWidget(outputDirLineEdit, 0, 1);
|
||||
layout->addWidget(headerLabel, 1, 0);
|
||||
layout->addWidget(headerLineEdit, 1, 1);
|
||||
layout->addWidget(implementationLabel, 2, 0);
|
||||
layout->addWidget(implementationLineEdit, 2, 1);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
//! [17]
|
||||
void OutputFilesPage::initializePage()
|
||||
{
|
||||
QString className = field("className").toString();
|
||||
headerLineEdit->setText(className.toLower() + ".h");
|
||||
implementationLineEdit->setText(className.toLower() + ".cpp");
|
||||
outputDirLineEdit->setText(QDir::toNativeSeparators(QDir::tempPath()));
|
||||
}
|
||||
//! [17]
|
||||
|
||||
ConclusionPage::ConclusionPage(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
setTitle(tr("Conclusion"));
|
||||
setPixmap(QWizard::WatermarkPixmap, QPixmap(":/images/watermark2.png"));
|
||||
|
||||
label = new QLabel;
|
||||
label->setWordWrap(true);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
layout->addWidget(label);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void ConclusionPage::initializePage()
|
||||
{
|
||||
QString finishText = wizard()->buttonText(QWizard::FinishButton);
|
||||
finishText.remove('&');
|
||||
label->setText(tr("Click %1 to generate the class skeleton.")
|
||||
.arg(finishText));
|
||||
}
|
119
tests/manual/examples/widgets/dialogs/classwizard/classwizard.h
Normal file
@ -0,0 +1,119 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef CLASSWIZARD_H
|
||||
#define CLASSWIZARD_H
|
||||
|
||||
#include <QWizard>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QCheckBox;
|
||||
class QGroupBox;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QRadioButton;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
//! [0]
|
||||
class ClassWizard : public QWizard
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ClassWizard(QWidget *parent = nullptr);
|
||||
|
||||
void accept() override;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
class IntroPage : public QWizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntroPage(QWidget *parent = nullptr);
|
||||
|
||||
private:
|
||||
QLabel *label;
|
||||
};
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
class ClassInfoPage : public QWizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ClassInfoPage(QWidget *parent = nullptr);
|
||||
|
||||
private:
|
||||
QLabel *classNameLabel;
|
||||
QLabel *baseClassLabel;
|
||||
QLineEdit *classNameLineEdit;
|
||||
QLineEdit *baseClassLineEdit;
|
||||
QCheckBox *qobjectMacroCheckBox;
|
||||
QGroupBox *groupBox;
|
||||
QRadioButton *qobjectCtorRadioButton;
|
||||
QRadioButton *qwidgetCtorRadioButton;
|
||||
QRadioButton *defaultCtorRadioButton;
|
||||
QCheckBox *copyCtorCheckBox;
|
||||
};
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
class CodeStylePage : public QWizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CodeStylePage(QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void initializePage() override;
|
||||
|
||||
private:
|
||||
QCheckBox *commentCheckBox;
|
||||
QCheckBox *protectCheckBox;
|
||||
QCheckBox *includeBaseCheckBox;
|
||||
QLabel *macroNameLabel;
|
||||
QLabel *baseIncludeLabel;
|
||||
QLineEdit *macroNameLineEdit;
|
||||
QLineEdit *baseIncludeLineEdit;
|
||||
};
|
||||
//! [3]
|
||||
|
||||
class OutputFilesPage : public QWizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OutputFilesPage(QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void initializePage() override;
|
||||
|
||||
private:
|
||||
QLabel *outputDirLabel;
|
||||
QLabel *headerLabel;
|
||||
QLabel *implementationLabel;
|
||||
QLineEdit *outputDirLineEdit;
|
||||
QLineEdit *headerLineEdit;
|
||||
QLineEdit *implementationLineEdit;
|
||||
};
|
||||
|
||||
class ConclusionPage : public QWizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ConclusionPage(QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void initializePage() override;
|
||||
|
||||
private:
|
||||
QLabel *label;
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,10 @@
|
||||
QT += widgets
|
||||
|
||||
HEADERS = classwizard.h
|
||||
SOURCES = classwizard.cpp \
|
||||
main.cpp
|
||||
RESOURCES = classwizard.qrc
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/dialogs/classwizard
|
||||
INSTALLS += target
|
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>images/background.png</file>
|
||||
<file>images/banner.png</file>
|
||||
<file>images/logo1.png</file>
|
||||
<file>images/logo2.png</file>
|
||||
<file>images/logo3.png</file>
|
||||
<file>images/watermark1.png</file>
|
||||
<file>images/watermark2.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 15 KiB |
26
tests/manual/examples/widgets/dialogs/classwizard/main.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
#include <QTranslator>
|
||||
#include <QLocale>
|
||||
#include <QLibraryInfo>
|
||||
|
||||
#include "classwizard.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
#ifndef QT_NO_TRANSLATION
|
||||
QString translatorFileName = QLatin1String("qtbase_");
|
||||
translatorFileName += QLocale::system().name();
|
||||
QTranslator *translator = new QTranslator(&app);
|
||||
if (translator->load(translatorFileName, QLibraryInfo::path(QLibraryInfo::TranslationsPath)))
|
||||
app.installTranslator(translator);
|
||||
#endif
|
||||
|
||||
ClassWizard wizard;
|
||||
wizard.show();
|
||||
return app.exec();
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(extension LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/dialogs/extension")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(extension
|
||||
finddialog.cpp finddialog.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(extension PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(extension PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
install(TARGETS extension
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
@ -0,0 +1,9 @@
|
||||
QT += widgets
|
||||
|
||||
HEADERS = finddialog.h
|
||||
SOURCES = finddialog.cpp \
|
||||
main.cpp
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/dialogs/extension
|
||||
INSTALLS += target
|
@ -0,0 +1,77 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#include "finddialog.h"
|
||||
|
||||
//! [0]
|
||||
FindDialog::FindDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
label = new QLabel(tr("Find &what:"));
|
||||
lineEdit = new QLineEdit;
|
||||
label->setBuddy(lineEdit);
|
||||
|
||||
caseCheckBox = new QCheckBox(tr("Match &case"));
|
||||
fromStartCheckBox = new QCheckBox(tr("Search from &start"));
|
||||
fromStartCheckBox->setChecked(true);
|
||||
|
||||
//! [1]
|
||||
findButton = new QPushButton(tr("&Find"));
|
||||
findButton->setDefault(true);
|
||||
|
||||
moreButton = new QPushButton(tr("&More"));
|
||||
moreButton->setCheckable(true);
|
||||
//! [0]
|
||||
moreButton->setAutoDefault(false);
|
||||
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
extension = new QWidget;
|
||||
|
||||
wholeWordsCheckBox = new QCheckBox(tr("&Whole words"));
|
||||
backwardCheckBox = new QCheckBox(tr("Search &backward"));
|
||||
searchSelectionCheckBox = new QCheckBox(tr("Search se&lection"));
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
buttonBox = new QDialogButtonBox(Qt::Vertical);
|
||||
buttonBox->addButton(findButton, QDialogButtonBox::ActionRole);
|
||||
buttonBox->addButton(moreButton, QDialogButtonBox::ActionRole);
|
||||
|
||||
connect(moreButton, &QAbstractButton::toggled, extension, &QWidget::setVisible);
|
||||
|
||||
QVBoxLayout *extensionLayout = new QVBoxLayout;
|
||||
extensionLayout->setContentsMargins(QMargins());
|
||||
extensionLayout->addWidget(wholeWordsCheckBox);
|
||||
extensionLayout->addWidget(backwardCheckBox);
|
||||
extensionLayout->addWidget(searchSelectionCheckBox);
|
||||
extension->setLayout(extensionLayout);
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
QHBoxLayout *topLeftLayout = new QHBoxLayout;
|
||||
topLeftLayout->addWidget(label);
|
||||
topLeftLayout->addWidget(lineEdit);
|
||||
|
||||
QVBoxLayout *leftLayout = new QVBoxLayout;
|
||||
leftLayout->addLayout(topLeftLayout);
|
||||
leftLayout->addWidget(caseCheckBox);
|
||||
leftLayout->addWidget(fromStartCheckBox);
|
||||
|
||||
QGridLayout *mainLayout = new QGridLayout;
|
||||
mainLayout->setSizeConstraint(QLayout::SetFixedSize);
|
||||
mainLayout->addLayout(leftLayout, 0, 0);
|
||||
mainLayout->addWidget(buttonBox, 0, 1);
|
||||
mainLayout->addWidget(extension, 1, 0, 1, 2);
|
||||
mainLayout->setRowStretch(2, 1);
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
setWindowTitle(tr("Extension"));
|
||||
//! [4] //! [5]
|
||||
extension->hide();
|
||||
}
|
||||
//! [5]
|
41
tests/manual/examples/widgets/dialogs/extension/finddialog.h
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef FINDDIALOG_H
|
||||
#define FINDDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QCheckBox;
|
||||
class QDialogButtonBox;
|
||||
class QGroupBox;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
//! [0]
|
||||
class FindDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FindDialog(QWidget *parent = nullptr);
|
||||
|
||||
private:
|
||||
QLabel *label;
|
||||
QLineEdit *lineEdit;
|
||||
QCheckBox *caseCheckBox;
|
||||
QCheckBox *fromStartCheckBox;
|
||||
QCheckBox *wholeWordsCheckBox;
|
||||
QCheckBox *searchSelectionCheckBox;
|
||||
QCheckBox *backwardCheckBox;
|
||||
QDialogButtonBox *buttonBox;
|
||||
QPushButton *findButton;
|
||||
QPushButton *moreButton;
|
||||
QWidget *extension;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif
|
16
tests/manual/examples/widgets/dialogs/extension/main.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "finddialog.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
FindDialog dialog;
|
||||
|
||||
dialog.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(fridgemagnets LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/draganddrop/fridgemagnets")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(fridgemagnets
|
||||
draglabel.cpp draglabel.h
|
||||
dragwidget.cpp dragwidget.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(fridgemagnets PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(fridgemagnets PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(fridgemagnets_resource_files
|
||||
"words.txt"
|
||||
)
|
||||
|
||||
qt_add_resources(fridgemagnets "fridgemagnets"
|
||||
PREFIX
|
||||
"/dictionary"
|
||||
FILES
|
||||
${fridgemagnets_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS fridgemagnets
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
@ -0,0 +1,51 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "draglabel.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
//! [0]
|
||||
DragLabel::DragLabel(const QString &text, QWidget *parent)
|
||||
: QLabel(parent)
|
||||
{
|
||||
QFontMetrics metric(font());
|
||||
QSize size = metric.size(Qt::TextSingleLine, text);
|
||||
|
||||
QImage image(size.width() + 12, size.height() + 12, QImage::Format_ARGB32_Premultiplied);
|
||||
image.fill(qRgba(0, 0, 0, 0));
|
||||
|
||||
QFont font;
|
||||
font.setStyleStrategy(QFont::ForceOutline);
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
QLinearGradient gradient(0, 0, 0, image.height()-1);
|
||||
gradient.setColorAt(0.0, Qt::white);
|
||||
gradient.setColorAt(0.2, QColor(200, 200, 255));
|
||||
gradient.setColorAt(0.8, QColor(200, 200, 255));
|
||||
gradient.setColorAt(1.0, QColor(127, 127, 200));
|
||||
|
||||
QPainter painter;
|
||||
painter.begin(&image);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setBrush(gradient);
|
||||
painter.drawRoundedRect(QRectF(0.5, 0.5, image.width()-1, image.height()-1),
|
||||
25, 25, Qt::RelativeSize);
|
||||
|
||||
painter.setFont(font);
|
||||
painter.setBrush(Qt::black);
|
||||
painter.drawText(QRect(QPoint(6, 6), size), Qt::AlignCenter, text);
|
||||
painter.end();
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
setPixmap(QPixmap::fromImage(image));
|
||||
m_labelText = text;
|
||||
}
|
||||
//! [2]
|
||||
|
||||
QString DragLabel::labelText() const
|
||||
{
|
||||
return m_labelText;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef DRAGLABEL_H
|
||||
#define DRAGLABEL_H
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QDragEnterEvent;
|
||||
class QDragMoveEvent;
|
||||
class QFrame;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
//! [0]
|
||||
class DragLabel : public QLabel
|
||||
{
|
||||
public:
|
||||
DragLabel(const QString &text, QWidget *parent);
|
||||
QString labelText() const;
|
||||
|
||||
private:
|
||||
QString m_labelText;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif // DRAGLABEL_H
|
@ -0,0 +1,176 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "draglabel.h"
|
||||
#include "dragwidget.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
static inline QString fridgetMagnetsMimeType() { return QStringLiteral("application/x-fridgemagnet"); }
|
||||
|
||||
//! [0]
|
||||
DragWidget::DragWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
QFile dictionaryFile(QStringLiteral(":/dictionary/words.txt"));
|
||||
dictionaryFile.open(QFile::ReadOnly);
|
||||
QTextStream inputStream(&dictionaryFile);
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
int x = 5;
|
||||
int y = 5;
|
||||
|
||||
while (!inputStream.atEnd()) {
|
||||
QString word;
|
||||
inputStream >> word;
|
||||
if (!word.isEmpty()) {
|
||||
DragLabel *wordLabel = new DragLabel(word, this);
|
||||
wordLabel->move(x, y);
|
||||
wordLabel->show();
|
||||
wordLabel->setAttribute(Qt::WA_DeleteOnClose);
|
||||
x += wordLabel->width() + 2;
|
||||
if (x >= 245) {
|
||||
x = 5;
|
||||
y += wordLabel->height() + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
QPalette newPalette = palette();
|
||||
newPalette.setColor(QPalette::Window, Qt::white);
|
||||
setPalette(newPalette);
|
||||
|
||||
setMinimumSize(400, qMax(200, y));
|
||||
setWindowTitle(tr("Fridge Magnets"));
|
||||
//! [2] //! [3]
|
||||
setAcceptDrops(true);
|
||||
}
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
void DragWidget::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
//! [4] //! [5]
|
||||
if (event->mimeData()->hasFormat(fridgetMagnetsMimeType())) {
|
||||
if (children().contains(event->source())) {
|
||||
event->setDropAction(Qt::MoveAction);
|
||||
event->accept();
|
||||
} else {
|
||||
event->acceptProposedAction();
|
||||
//! [5] //! [6]
|
||||
}
|
||||
//! [6] //! [7]
|
||||
} else if (event->mimeData()->hasText()) {
|
||||
event->acceptProposedAction();
|
||||
} else {
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
//! [7]
|
||||
|
||||
//! [8]
|
||||
void DragWidget::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasFormat(fridgetMagnetsMimeType())) {
|
||||
if (children().contains(event->source())) {
|
||||
event->setDropAction(Qt::MoveAction);
|
||||
event->accept();
|
||||
} else {
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
} else if (event->mimeData()->hasText()) {
|
||||
event->acceptProposedAction();
|
||||
} else {
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
//! [8]
|
||||
|
||||
//! [9]
|
||||
void DragWidget::dropEvent(QDropEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasFormat(fridgetMagnetsMimeType())) {
|
||||
const QMimeData *mime = event->mimeData();
|
||||
//! [9] //! [10]
|
||||
QByteArray itemData = mime->data(fridgetMagnetsMimeType());
|
||||
QDataStream dataStream(&itemData, QIODevice::ReadOnly);
|
||||
|
||||
QString text;
|
||||
QPoint offset;
|
||||
dataStream >> text >> offset;
|
||||
//! [10]
|
||||
//! [11]
|
||||
DragLabel *newLabel = new DragLabel(text, this);
|
||||
newLabel->move(event->position().toPoint() - offset);
|
||||
newLabel->show();
|
||||
newLabel->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
if (event->source() == this) {
|
||||
event->setDropAction(Qt::MoveAction);
|
||||
event->accept();
|
||||
} else {
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
//! [11] //! [12]
|
||||
} else if (event->mimeData()->hasText()) {
|
||||
QStringList pieces = event->mimeData()->text().split(
|
||||
QRegularExpression(QStringLiteral("\\s+")), Qt::SkipEmptyParts);
|
||||
QPoint position = event->position().toPoint();
|
||||
|
||||
for (const QString &piece : pieces) {
|
||||
DragLabel *newLabel = new DragLabel(piece, this);
|
||||
newLabel->move(position);
|
||||
newLabel->show();
|
||||
newLabel->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
position += QPoint(newLabel->width(), 0);
|
||||
}
|
||||
|
||||
event->acceptProposedAction();
|
||||
} else {
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
//! [12]
|
||||
|
||||
//! [13]
|
||||
void DragWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
//! [13]
|
||||
//! [14]
|
||||
DragLabel *child = static_cast<DragLabel*>(childAt(event->position().toPoint()));
|
||||
if (!child)
|
||||
return;
|
||||
|
||||
QPoint hotSpot = event->position().toPoint() - child->pos();
|
||||
|
||||
QByteArray itemData;
|
||||
QDataStream dataStream(&itemData, QIODevice::WriteOnly);
|
||||
dataStream << child->labelText() << QPoint(hotSpot);
|
||||
//! [14]
|
||||
|
||||
//! [15]
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
mimeData->setData(fridgetMagnetsMimeType(), itemData);
|
||||
mimeData->setText(child->labelText());
|
||||
//! [15]
|
||||
|
||||
//! [16]
|
||||
QDrag *drag = new QDrag(this);
|
||||
drag->setMimeData(mimeData);
|
||||
drag->setPixmap(child->pixmap());
|
||||
drag->setHotSpot(hotSpot);
|
||||
|
||||
child->hide();
|
||||
//! [16]
|
||||
|
||||
//! [17]
|
||||
if (drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::CopyAction) == Qt::MoveAction)
|
||||
child->close();
|
||||
else
|
||||
child->show();
|
||||
}
|
||||
//! [17]
|
@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef DRAGWIDGET_H
|
||||
#define DRAGWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QDragEnterEvent;
|
||||
class QDropEvent;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
//! [0]
|
||||
class DragWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
explicit DragWidget(QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif // DRAGWIDGET_H
|
@ -0,0 +1,12 @@
|
||||
QT += widgets
|
||||
|
||||
HEADERS = draglabel.h \
|
||||
dragwidget.h
|
||||
RESOURCES = fridgemagnets.qrc
|
||||
SOURCES = draglabel.cpp \
|
||||
dragwidget.cpp \
|
||||
main.cpp
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/draganddrop/fridgemagnets
|
||||
INSTALLS += target
|
@ -0,0 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/dictionary">
|
||||
<file>words.txt</file>
|
||||
</qresource>
|
||||
</RCC>
|
@ -0,0 +1,23 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "dragwidget.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
#ifdef QT_KEYPAD_NAVIGATION
|
||||
QApplication::setNavigationMode(Qt::NavigationModeCursorAuto);
|
||||
#endif
|
||||
DragWidget window;
|
||||
|
||||
bool smallScreen = QApplication::arguments().contains(QStringLiteral("-small-screen"));
|
||||
if (smallScreen)
|
||||
window.showFullScreen();
|
||||
else
|
||||
window.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
Colorless
|
||||
green
|
||||
ideas
|
||||
sleep
|
||||
furiously
|
||||
A
|
||||
colorless
|
||||
green
|
||||
idea
|
||||
is
|
||||
a
|
||||
new
|
||||
untried
|
||||
idea
|
||||
that
|
||||
is
|
||||
without
|
||||
vividness
|
||||
dull
|
||||
and
|
||||
unexciting
|
||||
To
|
||||
sleep
|
||||
furiously
|
||||
may
|
||||
seem
|
||||
a
|
||||
puzzling
|
||||
turn
|
||||
of
|
||||
phrase
|
||||
but
|
||||
the
|
||||
mind
|
||||
in
|
||||
sleep
|
||||
often
|
||||
indeed
|
||||
moves
|
||||
furiously
|
||||
with
|
||||
ideas
|
||||
and
|
||||
images
|
||||
flickering
|
||||
in
|
||||
and
|
||||
out
|
@ -0,0 +1,51 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(puzzle LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/draganddrop_puzzle")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(draganddrop_puzzle
|
||||
main.cpp
|
||||
mainwindow.cpp mainwindow.h
|
||||
pieceslist.cpp pieceslist.h
|
||||
puzzlewidget.cpp puzzlewidget.h
|
||||
)
|
||||
|
||||
set_target_properties(draganddrop_puzzle PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(draganddrop_puzzle PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(puzzle_resource_files
|
||||
"example.jpg"
|
||||
)
|
||||
|
||||
qt_add_resources(draganddrop_puzzle "puzzle"
|
||||
PREFIX
|
||||
"/images"
|
||||
FILES
|
||||
${puzzle_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS draganddrop_puzzle
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
BIN
tests/manual/examples/widgets/draganddrop/puzzle/example.jpg
Normal file
After Width: | Height: | Size: 42 KiB |
15
tests/manual/examples/widgets/draganddrop/puzzle/main.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
MainWindow window;
|
||||
window.loadImage(QStringLiteral(":/images/example.jpg"));
|
||||
window.show();
|
||||
return app.exec();
|
||||
}
|
118
tests/manual/examples/widgets/draganddrop/puzzle/mainwindow.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "pieceslist.h"
|
||||
#include "puzzlewidget.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <stdlib.h>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
{
|
||||
setupMenus();
|
||||
setupWidgets();
|
||||
|
||||
setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
|
||||
setWindowTitle(tr("Puzzle"));
|
||||
}
|
||||
|
||||
void MainWindow::openImage()
|
||||
{
|
||||
const QString directory =
|
||||
QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).value(0, QDir::homePath());
|
||||
QFileDialog dialog(this, tr("Open Image"), directory);
|
||||
dialog.setAcceptMode(QFileDialog::AcceptOpen);
|
||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||
QStringList mimeTypeFilters;
|
||||
for (const QByteArray &mimeTypeName : QImageReader::supportedMimeTypes())
|
||||
mimeTypeFilters.append(mimeTypeName);
|
||||
mimeTypeFilters.sort();
|
||||
dialog.setMimeTypeFilters(mimeTypeFilters);
|
||||
dialog.selectMimeTypeFilter("image/jpeg");
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
loadImage(dialog.selectedFiles().constFirst());
|
||||
}
|
||||
|
||||
void MainWindow::loadImage(const QString &fileName)
|
||||
{
|
||||
QPixmap newImage;
|
||||
if (!newImage.load(fileName)) {
|
||||
QMessageBox::warning(this, tr("Open Image"),
|
||||
tr("The image file could not be loaded."),
|
||||
QMessageBox::Close);
|
||||
return;
|
||||
}
|
||||
puzzleImage = newImage;
|
||||
setupPuzzle();
|
||||
}
|
||||
|
||||
void MainWindow::setCompleted()
|
||||
{
|
||||
QMessageBox::information(this, tr("Puzzle Completed"),
|
||||
tr("Congratulations! You have completed the puzzle!\n"
|
||||
"Click OK to start again."),
|
||||
QMessageBox::Ok);
|
||||
|
||||
setupPuzzle();
|
||||
}
|
||||
|
||||
void MainWindow::setupPuzzle()
|
||||
{
|
||||
int size = qMin(puzzleImage.width(), puzzleImage.height());
|
||||
puzzleImage = puzzleImage.copy((puzzleImage.width() - size) / 2,
|
||||
(puzzleImage.height() - size) / 2, size, size).scaled(puzzleWidget->width(),
|
||||
puzzleWidget->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
|
||||
piecesList->clear();
|
||||
|
||||
for (int y = 0; y < 5; ++y) {
|
||||
for (int x = 0; x < 5; ++x) {
|
||||
int pieceSize = puzzleWidget->pieceSize();
|
||||
QPixmap pieceImage = puzzleImage.copy(x * pieceSize, y * pieceSize, pieceSize, pieceSize);
|
||||
piecesList->addPiece(pieceImage, QPoint(x, y));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < piecesList->count(); ++i) {
|
||||
if (QRandomGenerator::global()->bounded(2) == 1) {
|
||||
QListWidgetItem *item = piecesList->takeItem(i);
|
||||
piecesList->insertItem(0, item);
|
||||
}
|
||||
}
|
||||
|
||||
puzzleWidget->clear();
|
||||
}
|
||||
|
||||
void MainWindow::setupMenus()
|
||||
{
|
||||
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
|
||||
|
||||
QAction *openAction = fileMenu->addAction(tr("&Open..."), this, &MainWindow::openImage);
|
||||
openAction->setShortcuts(QKeySequence::Open);
|
||||
|
||||
QAction *exitAction = fileMenu->addAction(tr("E&xit"), qApp, &QCoreApplication::quit);
|
||||
exitAction->setShortcuts(QKeySequence::Quit);
|
||||
|
||||
QMenu *gameMenu = menuBar()->addMenu(tr("&Game"));
|
||||
|
||||
gameMenu->addAction(tr("&Restart"), this, &MainWindow::setupPuzzle);
|
||||
}
|
||||
|
||||
void MainWindow::setupWidgets()
|
||||
{
|
||||
QFrame *frame = new QFrame;
|
||||
QHBoxLayout *frameLayout = new QHBoxLayout(frame);
|
||||
puzzleWidget = new PuzzleWidget(400);
|
||||
|
||||
piecesList = new PiecesList(puzzleWidget->pieceSize(), this);
|
||||
|
||||
|
||||
connect(puzzleWidget, &PuzzleWidget::puzzleCompleted,
|
||||
this, &MainWindow::setCompleted, Qt::QueuedConnection);
|
||||
|
||||
frameLayout->addWidget(piecesList);
|
||||
frameLayout->addWidget(puzzleWidget);
|
||||
setCentralWidget(frame);
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
// 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 <QPixmap>
|
||||
|
||||
class PiecesList;
|
||||
class PuzzleWidget;
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QListWidgetItem;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
void loadImage(const QString &path);
|
||||
|
||||
public slots:
|
||||
void openImage();
|
||||
void setupPuzzle();
|
||||
|
||||
private slots:
|
||||
void setCompleted();
|
||||
|
||||
private:
|
||||
void setupMenus();
|
||||
void setupWidgets();
|
||||
|
||||
QPixmap puzzleImage;
|
||||
PiecesList *piecesList;
|
||||
PuzzleWidget *puzzleWidget;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
@ -0,0 +1,87 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "pieceslist.h"
|
||||
|
||||
#include <QDrag>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QMimeData>
|
||||
|
||||
PiecesList::PiecesList(int pieceSize, QWidget *parent)
|
||||
: QListWidget(parent), m_PieceSize(pieceSize)
|
||||
{
|
||||
setDragEnabled(true);
|
||||
setViewMode(QListView::IconMode);
|
||||
setIconSize(QSize(m_PieceSize, m_PieceSize));
|
||||
setSpacing(10);
|
||||
setAcceptDrops(true);
|
||||
setDropIndicatorShown(true);
|
||||
}
|
||||
|
||||
void PiecesList::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasFormat(PiecesList::puzzleMimeType()))
|
||||
event->accept();
|
||||
else
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void PiecesList::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasFormat(PiecesList::puzzleMimeType())) {
|
||||
event->setDropAction(Qt::MoveAction);
|
||||
event->accept();
|
||||
} else {
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
void PiecesList::dropEvent(QDropEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasFormat(PiecesList::puzzleMimeType())) {
|
||||
QByteArray pieceData = event->mimeData()->data(PiecesList::puzzleMimeType());
|
||||
QDataStream dataStream(&pieceData, QIODevice::ReadOnly);
|
||||
QPixmap pixmap;
|
||||
QPoint location;
|
||||
dataStream >> pixmap >> location;
|
||||
|
||||
addPiece(pixmap, location);
|
||||
|
||||
event->setDropAction(Qt::MoveAction);
|
||||
event->accept();
|
||||
} else {
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
void PiecesList::addPiece(const QPixmap &pixmap, const QPoint &location)
|
||||
{
|
||||
QListWidgetItem *pieceItem = new QListWidgetItem(this);
|
||||
pieceItem->setIcon(QIcon(pixmap));
|
||||
pieceItem->setData(Qt::UserRole, QVariant(pixmap));
|
||||
pieceItem->setData(Qt::UserRole+1, location);
|
||||
pieceItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
|
||||
}
|
||||
|
||||
void PiecesList::startDrag(Qt::DropActions /*supportedActions*/)
|
||||
{
|
||||
QListWidgetItem *item = currentItem();
|
||||
|
||||
QByteArray itemData;
|
||||
QDataStream dataStream(&itemData, QIODevice::WriteOnly);
|
||||
QPixmap pixmap = qvariant_cast<QPixmap>(item->data(Qt::UserRole));
|
||||
QPoint location = item->data(Qt::UserRole+1).toPoint();
|
||||
|
||||
dataStream << pixmap << location;
|
||||
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
mimeData->setData(PiecesList::puzzleMimeType(), itemData);
|
||||
|
||||
QDrag *drag = new QDrag(this);
|
||||
drag->setMimeData(mimeData);
|
||||
drag->setHotSpot(QPoint(pixmap.width()/2, pixmap.height()/2));
|
||||
drag->setPixmap(pixmap);
|
||||
|
||||
if (drag->exec(Qt::MoveAction) == Qt::MoveAction)
|
||||
delete takeItem(row(item));
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef PIECESLIST_H
|
||||
#define PIECESLIST_H
|
||||
|
||||
#include <QListWidget>
|
||||
|
||||
class PiecesList : public QListWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PiecesList(int pieceSize, QWidget *parent = nullptr);
|
||||
void addPiece(const QPixmap &pixmap, const QPoint &location);
|
||||
|
||||
static QString puzzleMimeType() { return QStringLiteral("image/x-puzzle-piece"); }
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
void startDrag(Qt::DropActions supportedActions) override;
|
||||
|
||||
int m_PieceSize;
|
||||
};
|
||||
|
||||
#endif // PIECESLIST_H
|
17
tests/manual/examples/widgets/draganddrop/puzzle/puzzle.pro
Normal file
@ -0,0 +1,17 @@
|
||||
QT += widgets
|
||||
requires(qtConfig(filedialog))
|
||||
|
||||
HEADERS = mainwindow.h \
|
||||
pieceslist.h \
|
||||
puzzlewidget.h
|
||||
RESOURCES = puzzle.qrc
|
||||
SOURCES = main.cpp \
|
||||
mainwindow.cpp \
|
||||
pieceslist.cpp \
|
||||
puzzlewidget.cpp
|
||||
|
||||
QMAKE_PROJECT_NAME = dndpuzzle
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/draganddrop/puzzle
|
||||
INSTALLS += target
|
@ -0,0 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/images">
|
||||
<file>example.jpg</file>
|
||||
</qresource>
|
||||
</RCC>
|
@ -0,0 +1,167 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "puzzlewidget.h"
|
||||
#include "pieceslist.h"
|
||||
|
||||
#include <QDrag>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QMimeData>
|
||||
#include <QPainter>
|
||||
|
||||
PuzzleWidget::PuzzleWidget(int imageSize, QWidget *parent)
|
||||
: QWidget(parent), m_ImageSize(imageSize)
|
||||
{
|
||||
setAcceptDrops(true);
|
||||
setMinimumSize(m_ImageSize, m_ImageSize);
|
||||
setMaximumSize(m_ImageSize, m_ImageSize);
|
||||
}
|
||||
|
||||
void PuzzleWidget::clear()
|
||||
{
|
||||
pieces.clear();
|
||||
highlightedRect = QRect();
|
||||
inPlace = 0;
|
||||
update();
|
||||
}
|
||||
|
||||
void PuzzleWidget::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasFormat(PiecesList::puzzleMimeType()))
|
||||
event->accept();
|
||||
else
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void PuzzleWidget::dragLeaveEvent(QDragLeaveEvent *event)
|
||||
{
|
||||
QRect updateRect = highlightedRect;
|
||||
highlightedRect = QRect();
|
||||
update(updateRect);
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void PuzzleWidget::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
QRect updateRect = highlightedRect.united(targetSquare(event->position().toPoint()));
|
||||
|
||||
if (event->mimeData()->hasFormat(PiecesList::puzzleMimeType())
|
||||
&& findPiece(targetSquare(event->position().toPoint())) == -1) {
|
||||
|
||||
highlightedRect = targetSquare(event->position().toPoint());
|
||||
event->setDropAction(Qt::MoveAction);
|
||||
event->accept();
|
||||
} else {
|
||||
highlightedRect = QRect();
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
update(updateRect);
|
||||
}
|
||||
|
||||
void PuzzleWidget::dropEvent(QDropEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasFormat(PiecesList::puzzleMimeType())
|
||||
&& findPiece(targetSquare(event->position().toPoint())) == -1) {
|
||||
|
||||
QByteArray pieceData = event->mimeData()->data(PiecesList::puzzleMimeType());
|
||||
QDataStream dataStream(&pieceData, QIODevice::ReadOnly);
|
||||
Piece piece;
|
||||
piece.rect = targetSquare(event->position().toPoint());
|
||||
dataStream >> piece.pixmap >> piece.location;
|
||||
|
||||
pieces.append(piece);
|
||||
|
||||
highlightedRect = QRect();
|
||||
update(piece.rect);
|
||||
|
||||
event->setDropAction(Qt::MoveAction);
|
||||
event->accept();
|
||||
|
||||
if (piece.location == piece.rect.topLeft() / pieceSize()) {
|
||||
inPlace++;
|
||||
if (inPlace == 25)
|
||||
emit puzzleCompleted();
|
||||
}
|
||||
} else {
|
||||
highlightedRect = QRect();
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
int PuzzleWidget::findPiece(const QRect &pieceRect) const
|
||||
{
|
||||
for (int i = 0, size = pieces.size(); i < size; ++i) {
|
||||
if (pieces.at(i).rect == pieceRect)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void PuzzleWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
QRect square = targetSquare(event->position().toPoint());
|
||||
const int found = findPiece(square);
|
||||
|
||||
if (found == -1)
|
||||
return;
|
||||
|
||||
Piece piece = pieces.takeAt(found);
|
||||
|
||||
if (piece.location == square.topLeft() / pieceSize())
|
||||
inPlace--;
|
||||
|
||||
update(square);
|
||||
|
||||
QByteArray itemData;
|
||||
QDataStream dataStream(&itemData, QIODevice::WriteOnly);
|
||||
|
||||
dataStream << piece.pixmap << piece.location;
|
||||
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
mimeData->setData(PiecesList::puzzleMimeType(), itemData);
|
||||
|
||||
QDrag *drag = new QDrag(this);
|
||||
drag->setMimeData(mimeData);
|
||||
drag->setHotSpot(event->position().toPoint() - square.topLeft());
|
||||
drag->setPixmap(piece.pixmap);
|
||||
|
||||
if (drag->exec(Qt::MoveAction) != Qt::MoveAction) {
|
||||
pieces.insert(found, piece);
|
||||
update(targetSquare(event->position().toPoint()));
|
||||
|
||||
if (piece.location == square.topLeft() / pieceSize())
|
||||
inPlace++;
|
||||
}
|
||||
}
|
||||
|
||||
void PuzzleWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QPainter painter(this);
|
||||
painter.fillRect(event->rect(), Qt::white);
|
||||
|
||||
if (highlightedRect.isValid()) {
|
||||
painter.setBrush(QColor("#ffcccc"));
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.drawRect(highlightedRect.adjusted(0, 0, -1, -1));
|
||||
}
|
||||
|
||||
for (const Piece &piece : pieces)
|
||||
painter.drawPixmap(piece.rect, piece.pixmap);
|
||||
}
|
||||
|
||||
const QRect PuzzleWidget::targetSquare(const QPoint &position) const
|
||||
{
|
||||
QPoint topLeft = QPoint(position.x() / pieceSize(), position.y() / pieceSize()) * pieceSize();
|
||||
return QRect(topLeft, QSize(pieceSize(), pieceSize()));
|
||||
}
|
||||
|
||||
int PuzzleWidget::pieceSize() const
|
||||
{
|
||||
return m_ImageSize / 5;
|
||||
}
|
||||
|
||||
int PuzzleWidget::imageSize() const
|
||||
{
|
||||
return m_ImageSize;
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef PUZZLEWIDGET_H
|
||||
#define PUZZLEWIDGET_H
|
||||
|
||||
#include <QPoint>
|
||||
#include <QPixmap>
|
||||
#include <QList>
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QDragEnterEvent;
|
||||
class QDropEvent;
|
||||
class QMouseEvent;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class PuzzleWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PuzzleWidget(int imageSize, QWidget *parent = nullptr);
|
||||
void clear();
|
||||
|
||||
int pieceSize() const;
|
||||
int imageSize() const;
|
||||
|
||||
signals:
|
||||
void puzzleCompleted();
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dragLeaveEvent(QDragLeaveEvent *event) override;
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
struct Piece {
|
||||
QPixmap pixmap;
|
||||
QRect rect;
|
||||
QPoint location;
|
||||
};
|
||||
|
||||
int findPiece(const QRect &pieceRect) const;
|
||||
const QRect targetSquare(const QPoint &position) const;
|
||||
|
||||
QList<Piece> pieces;
|
||||
QRect highlightedRect;
|
||||
int inPlace;
|
||||
int m_ImageSize;
|
||||
};
|
||||
|
||||
#endif // PUZZLEWIDGET_H
|
@ -0,0 +1,49 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(fademessage LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/effects/fademessage")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(fademessage
|
||||
fademessage.cpp fademessage.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(fademessage PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(fademessage PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(fademessage_resource_files
|
||||
"background.jpg"
|
||||
)
|
||||
|
||||
qt_add_resources(fademessage "fademessage"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
${fademessage_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS fademessage
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
2
tests/manual/examples/widgets/effects/fademessage/README
Normal file
@ -0,0 +1,2 @@
|
||||
The background is taken from a public domain photo at:
|
||||
http://www.photos8.com/view/windows_problem_blue-800x600.html
|
BIN
tests/manual/examples/widgets/effects/fademessage/background.jpg
Normal file
After Width: | Height: | Size: 155 KiB |
@ -0,0 +1,91 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "fademessage.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
FadeMessage::FadeMessage(QWidget *parent): QGraphicsView(parent)
|
||||
{
|
||||
setScene(&m_scene);
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
||||
setupScene();
|
||||
|
||||
m_animation = new QPropertyAnimation(m_effect, "strength", this);
|
||||
m_animation->setDuration(500);
|
||||
m_animation->setEasingCurve(QEasingCurve::InOutSine);
|
||||
m_animation->setStartValue(0);
|
||||
m_animation->setEndValue(1);
|
||||
|
||||
setRenderHint(QPainter::Antialiasing, true);
|
||||
setFrameStyle(QFrame::NoFrame);
|
||||
}
|
||||
|
||||
void FadeMessage::togglePopup()
|
||||
{
|
||||
if (m_message->isVisible()) {
|
||||
m_message->setVisible(false);
|
||||
m_animation->setDirection(QAbstractAnimation::Backward);
|
||||
} else {
|
||||
m_message->setVisible(true);
|
||||
m_animation->setDirection(QAbstractAnimation::Forward);
|
||||
}
|
||||
m_animation->start();
|
||||
}
|
||||
|
||||
void FadeMessage::setupScene()
|
||||
{
|
||||
QGraphicsRectItem *parent = m_scene.addRect(0, 0, 800, 600);
|
||||
parent->setPen(Qt::NoPen);
|
||||
parent->setZValue(0);
|
||||
|
||||
QGraphicsPixmapItem *bg = m_scene.addPixmap(QPixmap(":/background.jpg"));
|
||||
bg->setParentItem(parent);
|
||||
bg->setZValue(-1);
|
||||
|
||||
for (int i = 1; i < 5; ++i)
|
||||
for (int j = 2; j < 5; ++j) {
|
||||
QGraphicsRectItem *item = m_scene.addRect(i * 50, (j - 1) * 50, 38, 38);
|
||||
item->setParentItem(parent);
|
||||
item->setZValue(1);
|
||||
int hue = 12 * (i * 5 + j);
|
||||
item->setBrush(QColor::fromHsv(hue, 128, 128));
|
||||
}
|
||||
|
||||
QFont font;
|
||||
font.setPointSize(font.pointSize() * 2);
|
||||
font.setBold(true);
|
||||
QFontMetrics fontMetrics(font);
|
||||
int fh = fontMetrics.height();
|
||||
|
||||
QString sceneText = "Qt Everywhere!";
|
||||
int sceneTextWidth = fontMetrics.horizontalAdvance(sceneText);
|
||||
|
||||
QGraphicsRectItem *block = m_scene.addRect(50, 300, sceneTextWidth, fh + 3);
|
||||
block->setPen(Qt::NoPen);
|
||||
block->setBrush(QColor(102, 153, 51));
|
||||
|
||||
QGraphicsTextItem *text = m_scene.addText(sceneText, font);
|
||||
text->setDefaultTextColor(Qt::white);
|
||||
text->setPos(50, 300);
|
||||
block->setZValue(2);
|
||||
block->hide();
|
||||
|
||||
text->setParentItem(block);
|
||||
m_message = block;
|
||||
|
||||
m_effect = new QGraphicsColorizeEffect;
|
||||
m_effect->setColor(QColor(122, 193, 66));
|
||||
m_effect->setStrength(0);
|
||||
m_effect->setEnabled(true);
|
||||
parent->setGraphicsEffect(m_effect);
|
||||
|
||||
QPushButton *press = new QPushButton;
|
||||
press->setText(tr("Press me"));
|
||||
connect(press, &QAbstractButton::clicked, this, &FadeMessage::togglePopup);
|
||||
m_scene.addWidget(press);
|
||||
|
||||
press->move(300, 500);
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef FADEMESSAGE_H
|
||||
#define FADEMESSAGE_H
|
||||
|
||||
#include <QGraphicsEffect>
|
||||
#include <QGraphicsView>
|
||||
#include <QPropertyAnimation>
|
||||
|
||||
#include "fademessage.h"
|
||||
|
||||
class FadeMessage: public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FadeMessage(QWidget *parent = nullptr);
|
||||
|
||||
private:
|
||||
void setupScene();
|
||||
|
||||
private slots:
|
||||
void togglePopup();
|
||||
|
||||
private:
|
||||
QGraphicsScene m_scene;
|
||||
QGraphicsColorizeEffect *m_effect;
|
||||
QGraphicsItem *m_message;
|
||||
QPropertyAnimation *m_animation;
|
||||
};
|
||||
|
||||
#endif // FADEMESSAGE_H
|
@ -0,0 +1,9 @@
|
||||
QT += widgets
|
||||
|
||||
SOURCES += main.cpp fademessage.cpp
|
||||
HEADERS += fademessage.h
|
||||
RESOURCES += fademessage.qrc
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/effects/fademessage
|
||||
INSTALLS += target
|
@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/" >
|
||||
<file>background.jpg</file>
|
||||
</qresource>
|
||||
</RCC>
|
18
tests/manual/examples/widgets/effects/fademessage/main.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "fademessage.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
FadeMessage widget;
|
||||
widget.setWindowTitle(QT_TRANSLATE_NOOP(QGraphicsView, "Popup Message with Effect"));
|
||||
widget.setFixedSize(400, 600);
|
||||
widget.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(embeddeddialogs LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/graphicsview/embeddeddialogs")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(embeddeddialogs
|
||||
customproxy.cpp customproxy.h
|
||||
embeddeddialog.cpp embeddeddialog.h embeddeddialog.ui
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(embeddeddialogs PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(embeddeddialogs PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(embeddeddialogs_resource_files
|
||||
"No-Ones-Laughing-3.jpg"
|
||||
)
|
||||
|
||||
qt_add_resources(embeddeddialogs "embeddeddialogs"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
${embeddeddialogs_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS embeddeddialogs
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
After Width: | Height: | Size: 30 KiB |
@ -0,0 +1,133 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "customproxy.h"
|
||||
|
||||
#include <QGraphicsScene>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionGraphicsItem>
|
||||
|
||||
CustomProxy::CustomProxy(QGraphicsItem *parent, Qt::WindowFlags wFlags)
|
||||
: QGraphicsProxyWidget(parent, wFlags), timeLine(new QTimeLine(250, this))
|
||||
{
|
||||
connect(timeLine, &QTimeLine::valueChanged,
|
||||
this, &CustomProxy::updateStep);
|
||||
connect(timeLine, &QTimeLine::stateChanged,
|
||||
this, &CustomProxy::stateChanged);
|
||||
}
|
||||
|
||||
QRectF CustomProxy::boundingRect() const
|
||||
{
|
||||
return QGraphicsProxyWidget::boundingRect().adjusted(0, 0, 10, 10);
|
||||
}
|
||||
|
||||
void CustomProxy::paintWindowFrame(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
QWidget *widget)
|
||||
{
|
||||
const QColor color(0, 0, 0, 64);
|
||||
|
||||
QRectF r = windowFrameRect();
|
||||
QRectF right(r.right(), r.top() + 10, 10, r.height() - 10);
|
||||
QRectF bottom(r.left() + 10, r.bottom(), r.width(), 10);
|
||||
bool intersectsRight = right.intersects(option->exposedRect);
|
||||
bool intersectsBottom = bottom.intersects(option->exposedRect);
|
||||
if (intersectsRight && intersectsBottom) {
|
||||
QPainterPath path;
|
||||
path.addRect(right);
|
||||
path.addRect(bottom);
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(color);
|
||||
painter->drawPath(path);
|
||||
} else if (intersectsBottom) {
|
||||
painter->fillRect(bottom, color);
|
||||
} else if (intersectsRight) {
|
||||
painter->fillRect(right, color);
|
||||
}
|
||||
|
||||
QGraphicsProxyWidget::paintWindowFrame(painter, option, widget);
|
||||
}
|
||||
|
||||
void CustomProxy::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
|
||||
{
|
||||
QGraphicsProxyWidget::hoverEnterEvent(event);
|
||||
scene()->setActiveWindow(this);
|
||||
if (qFuzzyCompare(timeLine->currentValue(), 1))
|
||||
zoomIn();
|
||||
}
|
||||
|
||||
void CustomProxy::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
|
||||
{
|
||||
QGraphicsProxyWidget::hoverLeaveEvent(event);
|
||||
if (!popupShown
|
||||
&& (timeLine->direction() != QTimeLine::Backward || qFuzzyIsNull(timeLine->currentValue()))) {
|
||||
zoomOut();
|
||||
}
|
||||
}
|
||||
|
||||
bool CustomProxy::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
|
||||
{
|
||||
if (watched->isWindow()
|
||||
&& (event->type() == QEvent::UngrabMouse || event->type() == QEvent::GrabMouse)) {
|
||||
popupShown = watched->isVisible();
|
||||
if (!popupShown && !isUnderMouse())
|
||||
zoomOut();
|
||||
}
|
||||
return QGraphicsProxyWidget::sceneEventFilter(watched, event);
|
||||
}
|
||||
|
||||
QVariant CustomProxy::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||
{
|
||||
if (change == ItemChildAddedChange || change == ItemChildRemovedChange) {
|
||||
if (change == ItemChildAddedChange) {
|
||||
currentPopup = qvariant_cast<QGraphicsItem *>(value);
|
||||
currentPopup->setCacheMode(ItemCoordinateCache);
|
||||
if (scene())
|
||||
currentPopup->installSceneEventFilter(this);
|
||||
} else if (scene()) {
|
||||
currentPopup->removeSceneEventFilter(this);
|
||||
currentPopup = nullptr;
|
||||
}
|
||||
} else if (currentPopup && change == ItemSceneHasChanged) {
|
||||
currentPopup->installSceneEventFilter(this);
|
||||
}
|
||||
return QGraphicsProxyWidget::itemChange(change, value);
|
||||
}
|
||||
|
||||
void CustomProxy::updateStep(qreal step)
|
||||
{
|
||||
QRectF r = boundingRect();
|
||||
setTransform(QTransform()
|
||||
.translate(r.width() / 2, r.height() / 2)
|
||||
.rotate(step * 30, Qt::XAxis)
|
||||
.rotate(step * 10, Qt::YAxis)
|
||||
.rotate(step * 5, Qt::ZAxis)
|
||||
.scale(1 + 1.5 * step, 1 + 1.5 * step)
|
||||
.translate(-r.width() / 2, -r.height() / 2));
|
||||
}
|
||||
|
||||
void CustomProxy::stateChanged(QTimeLine::State state)
|
||||
{
|
||||
if (state == QTimeLine::Running) {
|
||||
if (timeLine->direction() == QTimeLine::Forward)
|
||||
setCacheMode(ItemCoordinateCache);
|
||||
} else if (state == QTimeLine::NotRunning) {
|
||||
if (timeLine->direction() == QTimeLine::Backward)
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
}
|
||||
}
|
||||
|
||||
void CustomProxy::zoomIn()
|
||||
{
|
||||
if (timeLine->direction() != QTimeLine::Forward)
|
||||
timeLine->setDirection(QTimeLine::Forward);
|
||||
if (timeLine->state() == QTimeLine::NotRunning)
|
||||
timeLine->start();
|
||||
}
|
||||
|
||||
void CustomProxy::zoomOut()
|
||||
{
|
||||
if (timeLine->direction() != QTimeLine::Backward)
|
||||
timeLine->setDirection(QTimeLine::Backward);
|
||||
if (timeLine->state() == QTimeLine::NotRunning)
|
||||
timeLine->start();
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef CUSTOMPROXY_H
|
||||
#define CUSTOMPROXY_H
|
||||
|
||||
#include <QTimeLine>
|
||||
#include <QGraphicsProxyWidget>
|
||||
|
||||
class CustomProxy : public QGraphicsProxyWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CustomProxy(QGraphicsItem *parent = nullptr, Qt::WindowFlags wFlags = { });
|
||||
|
||||
QRectF boundingRect() const override;
|
||||
void paintWindowFrame(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
QWidget *widget) override;
|
||||
|
||||
protected:
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
|
||||
bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) override;
|
||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
|
||||
|
||||
private slots:
|
||||
void updateStep(qreal step);
|
||||
void stateChanged(QTimeLine::State);
|
||||
void zoomIn();
|
||||
void zoomOut();
|
||||
|
||||
private:
|
||||
QTimeLine *timeLine;
|
||||
QGraphicsItem *currentPopup = nullptr;
|
||||
bool popupShown = false;
|
||||
};
|
||||
|
||||
#endif // CUSTOMPROXY_H
|
@ -0,0 +1,70 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "embeddeddialog.h"
|
||||
#include "ui_embeddeddialog.h"
|
||||
|
||||
#include <QStyleFactory>
|
||||
|
||||
EmbeddedDialog::EmbeddedDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::EmbeddedDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->layoutDirection->setCurrentIndex(layoutDirection() != Qt::LeftToRight);
|
||||
|
||||
const QStringList styleKeys = QStyleFactory::keys();
|
||||
for (const QString &styleName : styleKeys) {
|
||||
ui->style->addItem(styleName);
|
||||
if (style()->objectName().toLower() == styleName.toLower())
|
||||
ui->style->setCurrentIndex(ui->style->count() - 1);
|
||||
}
|
||||
|
||||
connect(ui->layoutDirection, &QComboBox::activated,
|
||||
this, &EmbeddedDialog::layoutDirectionChanged);
|
||||
connect(ui->spacing, &QSlider::valueChanged,
|
||||
this, &EmbeddedDialog::spacingChanged);
|
||||
connect(ui->fontComboBox, &QFontComboBox::currentFontChanged,
|
||||
this, &EmbeddedDialog::fontChanged);
|
||||
connect(ui->style, &QComboBox::textActivated,
|
||||
this, &EmbeddedDialog::styleChanged);
|
||||
}
|
||||
|
||||
EmbeddedDialog::~EmbeddedDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void EmbeddedDialog::layoutDirectionChanged(int index)
|
||||
{
|
||||
setLayoutDirection(index == 0 ? Qt::LeftToRight : Qt::RightToLeft);
|
||||
}
|
||||
|
||||
void EmbeddedDialog::spacingChanged(int spacing)
|
||||
{
|
||||
layout()->setSpacing(spacing);
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
void EmbeddedDialog::fontChanged(const QFont &font)
|
||||
{
|
||||
setFont(font);
|
||||
}
|
||||
|
||||
static void setStyleHelper(QWidget *widget, QStyle *style)
|
||||
{
|
||||
widget->setStyle(style);
|
||||
widget->setPalette(style->standardPalette());
|
||||
const QObjectList children = widget->children();
|
||||
for (QObject *child : children) {
|
||||
if (QWidget *childWidget = qobject_cast<QWidget *>(child))
|
||||
setStyleHelper(childWidget, style);
|
||||
}
|
||||
}
|
||||
|
||||
void EmbeddedDialog::styleChanged(const QString &styleName)
|
||||
{
|
||||
QStyle *style = QStyleFactory::create(styleName);
|
||||
if (style)
|
||||
setStyleHelper(this, style);
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef EMBEDDEDDIALOG_H
|
||||
#define EMBEDDEDDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
class EmbeddedDialog;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class EmbeddedDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EmbeddedDialog(QWidget *parent = nullptr);
|
||||
~EmbeddedDialog();
|
||||
|
||||
private slots:
|
||||
void layoutDirectionChanged(int index);
|
||||
void spacingChanged(int spacing);
|
||||
void fontChanged(const QFont &font);
|
||||
void styleChanged(const QString &styleName);
|
||||
|
||||
private:
|
||||
Ui::EmbeddedDialog *ui;
|
||||
};
|
||||
|
||||
#endif // EMBEDDEDDIALOG_H
|
@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EmbeddedDialog</class>
|
||||
<widget class="QDialog" name="EmbeddedDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>407</width>
|
||||
<height>134</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Embedded Dialog</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Layout Direction:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>layoutDirection</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="layoutDirection">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Left to Right</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Right to Left</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Select Font:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>fontComboBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QFontComboBox" name="fontComboBox"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Style:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>style</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="style"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Layout spacing:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>spacing</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSlider" name="spacing">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -0,0 +1,18 @@
|
||||
QT += widgets
|
||||
requires(qtConfig(fontcombobox))
|
||||
|
||||
SOURCES += main.cpp
|
||||
SOURCES += customproxy.cpp embeddeddialog.cpp
|
||||
HEADERS += customproxy.h embeddeddialog.h
|
||||
|
||||
FORMS += embeddeddialog.ui
|
||||
RESOURCES += embeddeddialogs.qrc
|
||||
|
||||
build_all:!build_pass {
|
||||
CONFIG -= build_all
|
||||
CONFIG += release
|
||||
}
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/graphicsview/embeddeddialogs
|
||||
INSTALLS += target
|
@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource>
|
||||
<file>No-Ones-Laughing-3.jpg</file>
|
||||
</qresource>
|
||||
</RCC>
|
@ -0,0 +1,42 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "customproxy.h"
|
||||
#include "embeddeddialog.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsView>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
QGraphicsScene scene;
|
||||
scene.setStickyFocus(true);
|
||||
const int gridSize = 10;
|
||||
|
||||
for (int y = 0; y < gridSize; ++y) {
|
||||
for (int x = 0; x < gridSize; ++x) {
|
||||
CustomProxy *proxy = new CustomProxy(nullptr, Qt::Window);
|
||||
proxy->setWidget(new EmbeddedDialog);
|
||||
|
||||
QRectF rect = proxy->boundingRect();
|
||||
|
||||
proxy->setPos(x * rect.width() * 1.05, y * rect.height() * 1.05);
|
||||
proxy->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
|
||||
|
||||
scene.addItem(proxy);
|
||||
}
|
||||
}
|
||||
scene.setSceneRect(scene.itemsBoundingRect());
|
||||
|
||||
QGraphicsView view(&scene);
|
||||
view.scale(0.5, 0.5);
|
||||
view.setRenderHints(view.renderHints() | QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
|
||||
view.setBackgroundBrush(QPixmap(":/No-Ones-Laughing-3.jpg"));
|
||||
view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
|
||||
view.show();
|
||||
view.setWindowTitle("Embedded Dialogs Example");
|
||||
return app.exec();
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(flowlayout LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/graphicsview_flowlayout")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(graphicsview_flowlayout
|
||||
flowlayout.cpp flowlayout.h
|
||||
main.cpp
|
||||
window.cpp window.h
|
||||
)
|
||||
|
||||
set_target_properties(graphicsview_flowlayout PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(graphicsview_flowlayout PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
install(TARGETS graphicsview_flowlayout
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
@ -0,0 +1,170 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "flowlayout.h"
|
||||
|
||||
#include <QtMath>
|
||||
|
||||
FlowLayout::FlowLayout(QGraphicsLayoutItem *parent) : QGraphicsLayout(parent)
|
||||
{
|
||||
QSizePolicy sp = sizePolicy();
|
||||
sp.setHeightForWidth(true);
|
||||
setSizePolicy(sp);
|
||||
}
|
||||
|
||||
void FlowLayout::insertItem(int index, QGraphicsLayoutItem *item)
|
||||
{
|
||||
item->setParentLayoutItem(this);
|
||||
if (index > m_items.count() || index < 0)
|
||||
index = m_items.count();
|
||||
m_items.insert(index, item);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
int FlowLayout::count() const
|
||||
{
|
||||
return m_items.count();
|
||||
}
|
||||
|
||||
QGraphicsLayoutItem *FlowLayout::itemAt(int index) const
|
||||
{
|
||||
return m_items.value(index);
|
||||
}
|
||||
|
||||
void FlowLayout::removeAt(int index)
|
||||
{
|
||||
m_items.removeAt(index);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
qreal FlowLayout::spacing(Qt::Orientation o) const
|
||||
{
|
||||
return m_spacing[int(o) - 1];
|
||||
}
|
||||
|
||||
void FlowLayout::setSpacing(Qt::Orientations o, qreal spacing)
|
||||
{
|
||||
if (o & Qt::Horizontal)
|
||||
m_spacing[0] = spacing;
|
||||
if (o & Qt::Vertical)
|
||||
m_spacing[1] = spacing;
|
||||
}
|
||||
|
||||
void FlowLayout::setGeometry(const QRectF &geom)
|
||||
{
|
||||
QGraphicsLayout::setGeometry(geom);
|
||||
doLayout(geom, true);
|
||||
}
|
||||
|
||||
qreal FlowLayout::doLayout(const QRectF &geom, bool applyNewGeometry) const
|
||||
{
|
||||
qreal left, top, right, bottom;
|
||||
getContentsMargins(&left, &top, &right, &bottom);
|
||||
const qreal maxw = geom.width() - left - right;
|
||||
|
||||
qreal x = 0;
|
||||
qreal y = 0;
|
||||
qreal maxRowHeight = 0;
|
||||
QSizeF pref;
|
||||
for (QGraphicsLayoutItem *item : m_items) {
|
||||
pref = item->effectiveSizeHint(Qt::PreferredSize);
|
||||
maxRowHeight = qMax(maxRowHeight, pref.height());
|
||||
|
||||
qreal next_x;
|
||||
next_x = x + pref.width();
|
||||
if (next_x > maxw) {
|
||||
if (qFuzzyIsNull(x)) {
|
||||
pref.setWidth(maxw);
|
||||
} else {
|
||||
x = 0;
|
||||
next_x = pref.width();
|
||||
}
|
||||
y += maxRowHeight + spacing(Qt::Vertical);
|
||||
maxRowHeight = 0;
|
||||
}
|
||||
|
||||
if (applyNewGeometry)
|
||||
item->setGeometry(QRectF(QPointF(left + x, top + y), pref));
|
||||
x = next_x + spacing(Qt::Horizontal);
|
||||
}
|
||||
maxRowHeight = qMax(maxRowHeight, pref.height());
|
||||
return top + y + maxRowHeight + bottom;
|
||||
}
|
||||
|
||||
QSizeF FlowLayout::minSize(const QSizeF &constraint) const
|
||||
{
|
||||
QSizeF size(0, 0);
|
||||
qreal left, top, right, bottom;
|
||||
getContentsMargins(&left, &top, &right, &bottom);
|
||||
if (constraint.width() >= 0) { // height for width
|
||||
const qreal height = doLayout(QRectF(QPointF(0,0), constraint), false);
|
||||
size = QSizeF(constraint.width(), height);
|
||||
} else if (constraint.height() >= 0) { // width for height?
|
||||
// not supported
|
||||
} else {
|
||||
for (const QGraphicsLayoutItem *item : std::as_const(m_items))
|
||||
size = size.expandedTo(item->effectiveSizeHint(Qt::MinimumSize));
|
||||
size += QSizeF(left + right, top + bottom);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
QSizeF FlowLayout::prefSize() const
|
||||
{
|
||||
qreal left, right;
|
||||
getContentsMargins(&left, nullptr, &right, nullptr);
|
||||
|
||||
qreal maxh = 0;
|
||||
qreal totalWidth = 0;
|
||||
for (const QGraphicsLayoutItem *item : std::as_const(m_items)) {
|
||||
if (totalWidth > 0)
|
||||
totalWidth += spacing(Qt::Horizontal);
|
||||
QSizeF pref = item->effectiveSizeHint(Qt::PreferredSize);
|
||||
totalWidth += pref.width();
|
||||
maxh = qMax(maxh, pref.height());
|
||||
}
|
||||
maxh += spacing(Qt::Vertical);
|
||||
|
||||
const qreal goldenAspectRatio = 1.61803399;
|
||||
qreal w = qSqrt(totalWidth * maxh * goldenAspectRatio) + left + right;
|
||||
|
||||
return minSize(QSizeF(w, -1));
|
||||
}
|
||||
|
||||
QSizeF FlowLayout::maxSize() const
|
||||
{
|
||||
qreal totalWidth = 0;
|
||||
qreal totalHeight = 0;
|
||||
for (const QGraphicsLayoutItem *item : std::as_const(m_items)) {
|
||||
if (totalWidth > 0)
|
||||
totalWidth += spacing(Qt::Horizontal);
|
||||
if (totalHeight > 0)
|
||||
totalHeight += spacing(Qt::Vertical);
|
||||
QSizeF pref = item->effectiveSizeHint(Qt::PreferredSize);
|
||||
totalWidth += pref.width();
|
||||
totalHeight += pref.height();
|
||||
}
|
||||
|
||||
qreal left, top, right, bottom;
|
||||
getContentsMargins(&left, &top, &right, &bottom);
|
||||
return QSizeF(left + totalWidth + right, top + totalHeight + bottom);
|
||||
}
|
||||
|
||||
QSizeF FlowLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
|
||||
{
|
||||
QSizeF sh = constraint;
|
||||
switch (which) {
|
||||
case Qt::PreferredSize:
|
||||
sh = prefSize();
|
||||
break;
|
||||
case Qt::MinimumSize:
|
||||
sh = minSize(constraint);
|
||||
break;
|
||||
case Qt::MaximumSize:
|
||||
sh = maxSize();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return sh;
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef FLOWLAYOUT_H
|
||||
#define FLOWLAYOUT_H
|
||||
|
||||
#include <QGraphicsLayout>
|
||||
|
||||
class FlowLayout : public QGraphicsLayout
|
||||
{
|
||||
public:
|
||||
FlowLayout(QGraphicsLayoutItem *parent = nullptr);
|
||||
inline void addItem(QGraphicsLayoutItem *item);
|
||||
void insertItem(int index, QGraphicsLayoutItem *item);
|
||||
void setSpacing(Qt::Orientations o, qreal spacing);
|
||||
qreal spacing(Qt::Orientation o) const;
|
||||
|
||||
// inherited functions
|
||||
void setGeometry(const QRectF &geom) override;
|
||||
|
||||
int count() const override;
|
||||
QGraphicsLayoutItem *itemAt(int index) const override;
|
||||
void removeAt(int index) override;
|
||||
|
||||
protected:
|
||||
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const override;
|
||||
|
||||
private:
|
||||
qreal doLayout(const QRectF &geom, bool applyNewGeometry) const;
|
||||
QSizeF minSize(const QSizeF &constraint) const;
|
||||
QSizeF prefSize() const;
|
||||
QSizeF maxSize() const;
|
||||
|
||||
QList<QGraphicsLayoutItem *> m_items;
|
||||
qreal m_spacing[2] = {6, 6};
|
||||
};
|
||||
|
||||
|
||||
inline void FlowLayout::addItem(QGraphicsLayoutItem *item)
|
||||
{
|
||||
insertItem(-1, item);
|
||||
}
|
||||
|
||||
#endif // FLOWLAYOUT_H
|
@ -0,0 +1,10 @@
|
||||
QT += widgets
|
||||
|
||||
QMAKE_PROJECT_NAME = flowlayout_graphicsview
|
||||
|
||||
HEADERS += flowlayout.h window.h
|
||||
SOURCES += flowlayout.cpp main.cpp window.cpp
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/graphicsview/flowlayout
|
||||
INSTALLS += target
|
@ -0,0 +1,24 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
//! [1]
|
||||
#include "window.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QGraphicsView>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
QGraphicsScene scene;
|
||||
QGraphicsView view(&scene);
|
||||
Window *w = new Window;
|
||||
scene.addItem(w);
|
||||
|
||||
view.resize(400, 300);
|
||||
view.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
//! [1]
|
@ -0,0 +1,24 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "window.h"
|
||||
#include "flowlayout.h"
|
||||
|
||||
#include <QGraphicsProxyWidget>
|
||||
#include <QLabel>
|
||||
|
||||
Window::Window(QGraphicsItem *parent) : QGraphicsWidget(parent, Qt::Window)
|
||||
{
|
||||
FlowLayout *lay = new FlowLayout;
|
||||
const QString sentence(QLatin1String("I am not bothered by the fact that I am unknown."
|
||||
" I am bothered when I do not know others. (Confucius)"));
|
||||
const QList<QStringView> words = QStringView{ sentence }.split(QLatin1Char(' '), Qt::SkipEmptyParts);
|
||||
for (const QStringView &word : words) {
|
||||
QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(this);
|
||||
QLabel *label = new QLabel(word.toString());
|
||||
label->setFrameStyle(QFrame::Box | QFrame::Plain);
|
||||
proxy->setWidget(label);
|
||||
lay->addItem(proxy);
|
||||
}
|
||||
setLayout(lay);
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef WINDOW_H
|
||||
#define WINDOW_H
|
||||
|
||||
#include <QGraphicsWidget>
|
||||
|
||||
class Window : public QGraphicsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Window(QGraphicsItem *parent = nullptr);
|
||||
};
|
||||
|
||||
#endif // WINDOW_H
|