I tried to animate a tool button using QPropertyAnimation. However, it did nothing. Is there anything I have done wrong? Can anyone please help?
ToolBarPalettes.h:
class ToolBarPalettes : public QToolBar
{
public:
ToolBarPalettes(void);
~ToolBarPalettes(void);
public slots:
void startAnimation();
private:
createButtons();
QToolButton *animatedButton;
}
ToolBarPalettes.cpp:
ToolBarPalettes::ToolBarPalettes(void)
{
createButtons();
connect(animatedButton, SIGNAL(clicked()), this, SLOT(startAnimation()));
}
void ToolBarPalettes::createButtons()
{
animatedButton = new QToolButton;
animatedButton->setText("Animate!");
addWidget(animatedButton);
}
void ToolBarPalettes::startAnimation()
{
QPropertyAnimation *animation = new QPropertyAnimation(animatedButton, "geometry");
animation->setDuration(3000);
animation->setStartValue(QRect(this->x(), this->y(), this->width(), this->height()));
animation->setEndValue(QRect(this->x(), this->y(), 10, 10));
animation->setEasingCurve::OutBounce);
animation->start(QAbstractAnimation::DeleteWhenStopped);
}
You should use the minimumSize, maximumSize or size properties instead of the geometry property.
animation = new QPropertyAnimation(animatedButton, "minimumSize");
then set the values:
animation->setStartValue(animatedButton->minimumSize());
animation->setEndValue(QSize(100,100));
The geometry property only works for top-level windows and widget's that are not contained in a layout.
Related
I have set up a simple 3d scene with a custom QGeometryRenderer and QGeometry. The custom QGeometry is loaded from a ply file.
class ColorMeshGeometry : public Qt3DRender::QGeometry
{
Q_OBJECT
public:
ColorMeshGeometry(QString meshFile, ColorMeshRenderer *parent);
~ColorMeshGeometry();
void GeometryCenter(QVector3D* center);
};
class ColorMeshRenderer : public Qt3DRender::QGeometryRenderer
{
ColorMeshGeometry* m_geometry;
Q_OBJECT
public:
explicit ColorMeshRenderer(QString meshFile, Qt3DCore::QNode *parent = 0)
{
m_geometry = new ColorMeshGeometry(meshFile, this);
setGeometry(m_geometry);
}
~ColorMeshRenderer();
void ViewCenter(QVector3D* center);
};
And here is the code to set it all up:
uto view = new Qt3DExtras::Qt3DWindow();
auto container = createWindowContainer(view, this);
auto rootEntity = new Qt3DCore::QEntity();
ColorMeshRenderer* mesh = new ColorMeshRenderer(filename, rootEntity);
view->defaultFrameGraph()->setClearColor(QColor(QRgb(0x111111)));
view->camera()->lens()->setPerspectiveProjection(45.0f, view->width()/view->height(), 0.01f, 100000.0f);
view->camera()->setPosition(QVector3D(0.f, -512.f, 500.0f));
view->camera()->setViewCenter(QVector3D(0, 0, 0));
auto material = new Qt3DExtras::QPerVertexColorMaterial(rootEntity);
auto picker = new Qt3DRender::QObjectPicker(rootEntity);
picker->setHoverEnabled(false);
picker->setDragEnabled(false);
auto plyEntity = new Qt3DCore::QEntity(rootEntity);
plyEntity->addComponent(mesh);
plyEntity->addComponent(material);
plyEntity->addComponent(picker);
connect(picker, &Qt3DRender::QObjectPicker::pressed, this, &ViewerWidget::picker_Clicked);
Qt3DExtras::QOrbitCameraController *camController = new Qt3DExtras::QOrbitCameraController(rootEntity);
camController->setCamera(view->camera());
view->setRootEntity(rootEntity);
The QObjectPicker::pressed event is never fired. If I use the Qt3DExtras::QTorusMesh instead, the pressed event is fired. What else needs to be implemented for the QObjectPicker to work with a custom mesh?
Edit:
Full sample code can be found here.
The fix for this ended up being the Perspective Projection. The back pane of the project ended up being way to far way, the fix is:
view->camera()->lens()->setPerspectiveProjection(45.0f, view->width()/view->height(), 0.01f, 5000.0f);
I have a QHBoxLayout in which I added some widgets. I need to be able to refresh the layout dynamically so I use this to clear the layout :
void ClearLayout(QLayout* layout)
{
if (!layout)
return;
QLayoutItem* item;
while ((item = layout->takeAt(0)) != nullptr)
{
delete item->widget();
ClearLayout(item->layout());
}
}
This indeed removes all widgets and layouts. After this layout->isEmpty() returns true and layout->count() returns 0.
However, when I try to add new widgets (same type of other previously added but new instance) It does not work !
AddWidget()
{
// DeviceWidget inherits QWidget
DeviceWidget* deviceWidget = new DeviceWidget;
deviceWidget->setFixedSize(150, 200);
connect(deviceWidget->GetSignalObject(), &DeviceObject::Selected, this,
&DeviceLayout::SelectedDevice);
layout->addWidget(deviceWidget, 0, Qt::AlignCenter);
}
This is the same function used previously to add the widgets to the layout and worked the first time at Construction:
MainLayout(QWidget* parent) : QHBoxLayout(parent)
{
layout = new QHBoxLayout;
addLayout(layout);
uint32 nb = GetDeviceNumber(); // returns 2
for (uint32 i = 0; i < deviceNb; ++i)
AddDeviceWidget();
}
After trying to add 2 widgets I have layout->isEmpty() returns true and layout->count() returns 2 so I'm confused …
thanks for any help provided :)
EDIT:
The problem seems to be comming from my DeviceWidget class since trying to add a simple QLabel to the cleared layout worked. Here's the DeviceWidget Constructor:
DeviceWidget::DeviceWidget(QWidget* parent) : QWidget(parent)
{
QVBoxLayout* vLayout = new QVBoxLayout;
QLabel* deviceIcon = new QLabel("DeviceIcon", this);
deviceIcon->setFixedSize(128, 128);
deviceIcon->setPixmap(QPixmap::fromImage(QImage("Resources/Icons/device.png")));
deviceIcon->setObjectName("DeviceIcon");
// StatusWidget inherits QWidget
// Just override paintEvent to display a colored filled disk
m_status = new StatusWidget(20, Status::Close, this);
m_status->setObjectName("DeviceStatus");
vLayout->addWidget(deviceIcon, 0, Qt::AlignCenter);
vLayout->addWidget(m_status, 0, Qt::AlignCenter);
// DeviceObjct inherits from QObject an add a signal
m_object = new DeviceObject(size());
// Function clearing the stylesheet background-color
Clear();
setLayout(vLayout);
installEventFilter(this);
setObjectName(QString("DeviceWidget"));
}
Commenting installEventFilter(this) make it work so I think I need to add an event filter to make it work but I don't know which one
As said in the Edit, The problem is coming from DeviceWidget added in the layout that override eventFilter. There is probably a way to add a case in eventFilter to make it work but in my case it was best either (1) or (2):
1. Remove eventFilter from class DeviceWidget and put it in class DeviceObject: m_object is present to emit a signal according to event:
DeviceObject.h:
DeviceObject(QObject* parent);
bool eventFilter(QObject* obj, QEvent* event) override;
signals:
void Select(uint32 i);
Then in class DeviceWidget still call installEventFilter but with m_object as parameter: installEventFilter(m_object);
For the other event (Enter/Leave) I overrode void enterEvent(QEvent* event) and void leaveEvent(QEvent* event) for class DeviceWidget. That's what lead me to the second option that seems better.
2. Completely remove eventFilter and installEventFilter as it is only used to emit a signal when widget is clicked and do things when cursor hovers the widget. Instead override enterEvent and leaveEvent for class DeviceWidget like said before for hover event.
Then in class DeviceObjecy override void mousePressEvent(QMouseEvent*) for clicked event.
I am new to QT. I have several QDialogs in my QT project. I have created a generic class to change the properties of widgets inside QDialogs. My generic class has a static method which will change the properties of widgets.
void MyClass::setFontsizeToWidgets(float modValue, QObject obj)
{
QFont f;
float pointSize = 0.0;
QList<QPushButton*> buttons = obj.findChildren<QPushButton*>();
foreach ( QPushButton * button, buttons)
{
f = button->font();
pointSize = f.pointSizeF();
f.setPointSizeF(pointSize*modValue);
button->setFont(f);
}
}
Now my questions is, how to pass the QDialog as a object to the above static method from QDialog class? So that the static method will change the font size of the QPushButton(s) in the QDialog.
You can do it like this:
void MyClass::setFontsizeToWidgets(float modValue, QObject *obj)
{
//do something
}
void MyDialog::someFunction() //this is a function of your QDialog class
{
MyClass::setFontsizeToWidgets(10, this);
}
I am new to Qt. As it stands, I have a table with a button btn. When the button is clicked the setCentralWidget(view) takes over the window so I can no longer see the table obviously. But if I remove the setCentralWidget(view), nothing displays when I click the button.
Is there a way I can display both in the same window? Split or dock maybe?
(I have removed code that is irrelevant to my question)
MainWindow::MainWindow()
{
//etc
packet = new QTabWidget;
setCentralWidget(packet)
}
//other code
void MainWindow::create(const QString &a)
{
QTableWidget* table = new QTableWidget;
int tabIndex = packet->addTab(table, a);
packet->setCurrentIndex(tabIndex);
table->setRowCount(1);
table->setColumnCount(2);
table->setHorizontalHeaderLabels(QString("a;Simulator").split(";"));"));
table->setItem(0,0,new QTableWidgetItem(a));
QPushButton *btn = new QPushButton("load", this);
connect(btn, SIGNAL(clicked()), this, SLOT(sim()));
table->setCellWidget(0,1, btn);
}
void MainWindow::sim()
{
QGraphicsScene* scene = new QGraphicsScene(QRect(-10, -10, 100, 50));
QGraphicsView* view = new QGraphicsView();
scene->addText("Network");
view->setScene(scene);
view->setGeometry(QRect(10, 10, 100, 50));
setCentralWidget(view);
}
You should look at the QMdiArea class - it's designed to be used as the central widget of a Main Window that can have many inner widgets. It has a variety of layout styles as well - scroll down on that page to see the examples.
Hope that helps!
You should subclass QWidget. For example make your own MyWidget class. And this class will include a QGraphicsView and a QTabWidget in a splitter for example. And in your MainWindow set the central widget as an instance of MyWidget.
I'm trying to implement drag'n'drop for a QGraphicsScene. Here are the events I've overloaded:
void TargetScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event) {
bool acceptDrag = false;
const QMimeData* mime = event->mimeData();
// Is an image present?
if (mime->hasImage()) {
QImage img = qvariant_cast<QImage>(mime->imageData());
dragPix = QPixmap::fromImage(img);
acceptDrag = !dragPix.isNull();
}
event->setAccepted(acceptDrag);
}
void TargetScene::dropEvent(QGraphicsSceneDragDropEvent *event) {
// Add dragged pixmap to scene
QGraphicsPixmapItem* newPix = this->addPixmap(dragPix);
newPix->setPos(event->pos().x(), event->pos().y());
}
The scene still won't accept drops. I'm guessing that's because I can't do setAcceptDrops(true) on my QGraphicsScene.
How do I accept drops on a graphics scene?
The trick here is to ALSO accept the event in the QGraphicsScene::dragMoveEvent()!
The reason is the DEFAULT implementation which ignores drag and drop events if there is no item under the mouse!
Also refer to: http://www.qtcentre.org/threads/8022-QGraphicsScene-doesn-t-accept-Drops
Cheers