I had a segmentation fault when using my new Qt Widget with Qt Designer 4.6. The problem arise when trying to preview the new widget.
when using gdb I found that the problem is in qdesigner_internal::WidgetFactory::applyStyleToTopLevel:
Program received signal SIGSEGV, Segmentation fault.
qdesigner_internal::WidgetFactory::applyStyleToTopLevel (style=0x0, widget=0x1829df0) at /var/tmp/qt-x11-src-4.6.0/tools/designer/src/lib/shared/widgetfactory.cpp:777
777 /var/tmp/qt-x11-src-4.6.0/tools/designer/src/lib/shared/widgetfactory.cpp: No such file or directory.
in /var/tmp/qt-x11-src-4.6.0/tools/designer/src/lib/shared/widgetfactory.cpp
(gdb) bt
#0 qdesigner_internal::WidgetFactory::applyStyleToTopLevel (style=0x0, widget=0x1829df0) at /var/tmp/qt-x11-src-4.6.0/tools/designer/src/lib/shared/widgetfactory.cpp:777
#1 0x00007ffff7475bed in qdesigner_internal::QDesignerFormBuilder::createPreview (fw=, styleName=..., appStyleSheet=..., deviceProfile=, scriptErrors=
0x7fffffffbee0, errorMessage=0x7fffffffc3f0) at /var/tmp/qt-x11-src-4.6.0/tools/designer/src/lib/shared/qdesigner_formbuilder.cpp:404
#2 0x00007ffff7476773 in qdesigner_internal::QDesignerFormBuilder::createPreview (fw=0x0, styleName=..., appStyleSheet=..., deviceProfile=..., errorMessage=0x0)
at /var/tmp/qt-x11-src-4.6.0/tools/designer/src/lib/shared/qdesigner_formbuilder.cpp:439
#3 0x00007ffff7532b27 in qdesigner_internal::PreviewManager::createPreview (this=0x837f20, fw=0x1879200, pc=..., deviceProfileIndex=-1, errorMessage=0x7fffffffc3f0, initialZoom=-1)
at /var/tmp/qt-x11-src-4.6.0/tools/designer/src/lib/shared/previewmanager.cpp:686
#4 0x00007ffff75343cf in qdesigner_internal::PreviewManager::showPreview (this=0x837f20, fw=0x1879200, pc=..., deviceProfileIndex=-1, errorMessage=0x7fffffffc3f0)
at /var/tmp/qt-x11-src-4.6.0/tools/designer/src/lib/shared/previewmanager.cpp:760
#5 0x00007ffff753472f in qdesigner_internal::PreviewManager::showPreview (this=0x837f20, fw=0x1879200, style=..., deviceProfileIndex=-1, errorMessage=0x7fffffffc3f0)
at /var/tmp/qt-x11-src-4.6.0/tools/designer/src/lib/shared/previewmanager.cpp:659
because a null pointer was passed there:
void WidgetFactory::applyStyleToTopLevel(QStyle *style, QWidget *widget)
{
const QPalette standardPalette = style->standardPalette();
if (widget->style() == style && widget->palette() == standardPalette)
return;
//....
}
I'm new in Qt and this is my first custom widget. does anybody have a clue for solving this.
here is my widget code
MBICInput::MBICInput(QWidget *parent) : QStackedWidget(parent){
displayPage = new QWidget();
displayPage->setObjectName(QString::fromUtf8("displayPage"));
inputLB = new QLabel(displayPage);
inputLB->setObjectName(QString::fromUtf8("inputLabel"));
inputLB->setCursor(QCursor(Qt::PointingHandCursor));
addWidget(displayPage);
EditPage = new QWidget();
EditPage->setProperty("EditInputLine", QVariant(true));
EditPage->setObjectName(QString::fromUtf8("EditPage"));
inputInput = new QLineEdit(EditPage);
inputInput->setGeometry(QRect(5, 10, 231, 25));
inputInput->setObjectName(QString::fromUtf8("input"));
addWidget(EditPage);
_animation = new QString("");
_message = new QString("Message");
_validator = new QRegExpValidator(QRegExp("[a-zA-Z]+"), this);
}
MBICInput::~MBICInput() {
}
QValidator::State MBICInput::validate(QString &text, int &pos) const{
return _validator->validate(text, pos);
}
void MBICInput::paintEvent(QPaintEvent *) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
}
QSize MBICInput::minimumSizeHint() const{
return QSize(200, 40);
}
QSize MBICInput::sizeHint() const{
return QSize(200, 40);
}
void MBICInput::setAnimation(const QString &animation){
*_animation = animation;
update();
}
QString MBICInput::animation() const{
return *_animation;
}
void MBICInput::setMessage(const QString &message){
*_message = message;
update();
}
QString MBICInput::message() const{
return *_message;
}
void MBICInput::mousePressEvent(QMouseEvent *event){
if(currentIndex()==0){
setCurrentIndex(1);
}else{
setCurrentIndex(0);
}
update();
}
In the applyStyleToTopLevel function, you are using the widget pointers without verifying it's a valid pointer. So when doing widget->style with a NULL widget pointer it will crash.
Just for information I just compiled the same code under the Qt version 4.5.3-9 and it worked just fine with the 4.5 designer. may be it's a Qt 4.6 bug...
Related
I was going through a code.
void GZMainWindow::connectMarkers_cx()
{
//![1]
// Connect all markers to handler
const auto markers = cx_chart->legend()->markers();
for (QLegendMarker *marker : markers)
{
QObject::disconnect(marker, &QLegendMarker::clicked,
this, &GZMainWindow::handleMarkerClicked);
QObject::connect(marker, &QLegendMarker::clicked, this, &GZMainWindow::handleMarkerClicked);
}
//![1]
}
What does //![1] mean? Is it used for segmentation of code or function ?
A project uses custom frame widget that implements a kind of "cover" that hides widgets (think of it as of security cover that prevents pressing buttons).This is a required visual design. Qt version is 4.6
#ifndef CQFRAME_H
#define CQFRAME_H
#include <QFrame>
#include <QtDesigner/QDesignerExportWidget>
//! [0] //! [1]
class CQFrame : public QFrame
// our agreement about "custom" widgets is to start them with CQ
{
Q_OBJECT
Q_ENUMS(FrameColorStyle)
Q_PROPERTY(FrameColorStyle colorStyle READ getColorStyle WRITE setColorStyle)
Q_PROPERTY(bool border READ border WRITE setBorder)
//! [0]
private:
bool curCover;
QFrame *frameCover;
public:
enum FrameColorStyle {fcDark, fcLight, fcTransparent, fcSystemDefault, fcRed, fcGreen, fcBlue};
CQFrame(QWidget *parent = 0);
void setCoverPropertie();
void setCover(bool state);
protected:
void resizeEvent(QResizeEvent *event);
FrameColorStyle m_colorStyle;
QString pstylebord;
bool m_border;
//! [2]
};
//! [1] //! [2]
#endif
I omitted getters and setters that are irrelevant to the problem. Here is implementation:
void CQFrame::setCoverPropertie()
{
QString str, strAlpha, gradient1, gradient2;
strAlpha.setNum(200);
gradient1 = "rgba("+str.setNum(cwDisableColor.red())+", "
+str.setNum(cwDisableColor.green())
+", "+str.setNum(cwDisableColor.blue())
+" ," +strAlpha+ " )";
gradient2 = "rgba("+str.setNum(cwLbColor.red())+", "
+str.setNum(cwLbColor.green())+", "
+str.setNum(cwLbColor.blue())+" ," +strAlpha+ " )";
QStackedLayout *stackedLayout = new QStackedLayout(this);
frameCover = new QFrame(this);
frameCover->setGeometry(rect());
frameCover->setStyleSheet("QFrame{border:5px solid "+strLbColor+"; "
"border-radius: 10px; background-color: "
"qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.5, stop: 0 "
+gradient1+" , stop: 1 "+gradient2+"); }");
stackedLayout->addWidget(frameCover);
stackedLayout->setStackingMode(QStackedLayout::StackAll);
}
void CQFrame::setCover(bool state)
{
frameCover->setVisible(curCover = state);
}
void CQFrame::resizeEvent(QResizeEvent *event)
{
if (curCover)
frameCover->setGeometry(rect());
}
The design isn't mine, I was asked to fix strange visual glitches it experiences. This "frame" is used in Qt designer as one of widgets. After a while suddenly everything resizes, which prompted question "what is wrong with this code". Qt fires warning about attempt to add layout while one already exist: I suppose that may cause a problem, because a frame must have only one layout at time? Code generated by Qt Creator looks something like
void setupUi(CQFrame *CQWnd1T2SeparateONForm)
{
if (CQWnd1T2SeparateONForm->objectName().isEmpty())
CQWnd1T2SeparateONForm->setObjectName(QString::fromUtf8("CQWnd1T2SeparateONForm"));
CQWnd1T2SeparateONForm->resize(735, 241);
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
sizePolicy.setHeightForWidth(CQWnd1T2SeparateONForm->sizePolicy().hasHeightForWidth());
CQWnd1T2SeparateONForm->setSizePolicy(sizePolicy);
gridLayout = new QGridLayout(CQWnd1T2SeparateONForm); // warning here
}
There is similar problem with standard QMainWindow which always got own "special" layout, which Qt Creator solves automatically, by adding a central widget to the layout and everything else is added to that widget. What I don't know that is how to simulate same behavior with a custom widget with Qt Creator plugin.
Or what alternative design for CQFrame can be used. CQFrame reused in dozen project, in about 30+ panels, so reuse of code for them all is a strict requirement.
Current plugin is very basic:
class QDESIGNER_WIDGET_EXPORT CQFramePlugin : public QObject,
public QDesignerCustomWidgetInterface
{
Q_OBJECT
Q_INTERFACES(QDesignerCustomWidgetInterface)
public:
CQFramePlugin(QObject *parent = 0);
bool isContainer() const;
bool isInitialized() const;
QIcon icon() const;
QString domXml() const;
QString group() const;
QString includeFile() const;
QString name() const;
QString toolTip() const;
QString whatsThis() const;
QWidget *createWidget(QWidget *parent);
void initialize(QDesignerFormEditorInterface *core);
private:
bool initialized;
};
.cpp for it:
#include "cqframe.h"
#include "cqframeplugin.h"
#include <QtPlugin>
CQFramePlugin::CQFramePlugin(QObject *parent)
: QObject(parent)
{
initialized = false;
}
void CQFramePlugin::initialize(QDesignerFormEditorInterface * /* core */)
{
if (initialized)
return;
initialized = true;
}
bool CQFramePlugin::isInitialized() const
{
return initialized;
}
QWidget *CQFramePlugin::createWidget(QWidget *parent)
{
return new CQFrame(parent);
}
QString CQFramePlugin::name() const
{
return "CQFrame";
}
QString CQFramePlugin::group() const
{
return "CustomWidgets";
}
QIcon CQFramePlugin::icon() const
{
return QIcon(":/Resources/frame_icon.png");
}
QString CQFramePlugin::toolTip() const
{
return "";
}
QString CQFramePlugin::whatsThis() const
{
return "";
}
bool CQFramePlugin::isContainer() const
{
return true;
}
QString CQFramePlugin::domXml() const
{
return "<ui language=\"c++\">\n"
" <widget class=\"CQFrame\" name=\"Frame\">\n"
" <property name=\"geometry\">\n"
" <rect>\n"
" <x>0</x>\n"
" <y>0</y>\n"
" <width>120</width>\n"
" <height>80</height>\n"
" </rect>\n"
" </property>\n"
" </widget>\n"
"</ui>";
}
QString CQFramePlugin::includeFile() const
{
return "cqframe.h";
}
So I haven't worked with QT yet, but I'm going to gie it a try. First thing, I think, is that you should use the QStackedLayout to cover the widgets (source and QT manual). But you need to have a single stack.
So the stack should be a private member of CQFrame. E.g.
class CQFrame : public QFrame
{
[...]
private:
QWidget* _frame; // Frame to cover.
QFrame* _frameCover;
QStackedLayout* _stackedLayout;
[...]
And probably:
CQFrame::~CQFrame()
{
delete _stackedLayout;
delete _frameCover;
}
Then you could already initialize everything in the constructor
CQFrame::CQFrame(QWidget* parent = 0, QWidget* frame)
: QFrame(parent)
, _frame(frame)
, _frameCover(new QFrame(this))
, _stackedLayout(new QStackedLayout(this))
{
_frameCover->setGeometry(rect());
[...]
_stackedLayout->addWidget(frame);
_stackedLayout->addWidget(frameCover);
//default:_stackedLayout->setStackingMode(QStackedLayout::StackOne);
}
You could then switch between widgets in the stack using
void CQFrame::SetCover(bool state)
{
if (state) _stackedLayout->setCurrentWidget(_frameCover);
else _stackedLayout->setCurrentWidget(_frame);
}
Maybe this helps you.
edit2:
I removed this code, as it was incorrect, both in coding format, as in idea
So I checked the QT sources QStackedLayout.cpp and QLayout and it seems a QWidget can have only one layout. If you add another layout, you get an error.
Furthermore, a QStackedLayout is a QLayout, is QObject. That could indicate it is automatically removed?
I'm not sure of the cover is implemented in QT as it should. It seems like you have a QWidget you want to cover, on top of which you put a QStackedLayout that is not used as designed i.e. switching stack objects, on top of which you put a new QWidget that is made visible or not.
And maybe that bottom QWidget is already in a (stacked)layout, etc.
I am trying to do undo/redo on multidocument interface but facing following error:
no matching function for call to 'qobject_cast(QMdiSubWindow*&)'
return qobject_cast<CadGraphicsView *>(activeSubWindow);
My code to above function is as follows:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
m_undoGroup = new QUndoGroup(this);
QAction *undoAction = m_undoGroup->createUndoAction(this);
undoAction->setShortcut(QKeySequence::Undo);
QAction *redoAction = m_undoGroup->createRedoAction(this);
redoAction->setShortcut(QKeySequence::Redo);
menuEdit->insertAction(menuEdit->actions().at(0), undoAction);
menuEdit->insertAction(undoAction, redoAction);
menuEdit->addAction(undoAction);
menuEdit->addAction(redoAction);
updateActions();
}
void MainWindow::setCurrentDocument()
{
mdiArea->currentSubWindow();
}
void MainWindow::addnewFile()
{
m_undoGroup->addStack(view->scene->undoStack());
connect(view->scene->undoStack(), SIGNAL(indexChanged(int)), this, SLOT(updateActions()));
connect(view->scene->undoStack(), SIGNAL(cleanChanged(bool)), this, SLOT(updateActions()));
}
void MainWindow::updateActions()
{
CadGraphicsScene *scene = currentDocument();
m_undoGroup->setActiveStack(scene == 0 ? 0 : scene->undoStack());
}
CadGraphicsView *MainWindow::currentDocument() const
{
if (QMdiSubWindow *activeSubWindow = mdiArea->currentSubWindow())
return qobject_cast<CadGraphicsView *>(activeSubWindow);
return 0;
}
void MainWindow::newFile()
{
// creates a new file
createMdiView();
view->newFile();
addnewFile();
curFileName = tr("Document %1").arg(++fileNumber);
view->setWindowTitle(curFileName);
view->scene->installEventFilter(this);
view->show();
isEntitySelected = false;
}
CadGraphicsView *MainWindow::createMdiView()
{
// creates a graphicsView and add it to the MDI window
view = new CadGraphicsView;
QMdiSubWindow *w = mdiArea->addSubWindow(view);
mdiArea->setActiveSubWindow(w);
windowViewList.append(qMakePair(w, view));
return view;
}
Can you please help me to solve the error. I have added the basic idea how it is working.
Got the solution to my problem. I need to change the currentDocument function as follows:
CadGraphicsView *MainWindow::currentDocument() const
{
return qobject_cast<CadGraphicsView *>(mdiArea->parentWidget());
}
I've been struggling with a really strange behavior that I do not manage to resolve on my own, so here I am.
I'm creating an GUI for a console application which works great. The user can either select a file to be loaded or reload a previous selected file. Those two actions are handled with two different slots. I'm handling errors in the file's format with exceptions and it worked great in the console version, but for the GUI not too well for the moment...
When an error is thrown in the openFile slot, the catch block makes his work and the method is stopped as expected BUT then the other slot is being called unexpectedly. I have no idea why and so have no idea how to correct that behavior.
Here's the relevant code :
void Loader::openSourceFile()
{
fileName = QFileDialog::getOpenFileName(myWindow, tr("Select source file"), QString(), tr("Text files (*.txt)"));
try{
parseSourceFile();
} catch(MyException &e)
{
QString msg = QString(e.what());
myWindow->alertUser(msg);
return;
}
}
void Loader::reloadSourceFile()
{
try{
parseSourceFile();
} catch(MyException &e)
{
QString msg = QString(e.what());
myWindow->alertUser(msg);
return;
}
}
the context of use :
myLoader = new Loader(this);
menuTop = menuBar()->addMenu(tr("&File"));
//open source file
openAction = new QAction(QIcon(":images/document.png"), tr("&Open"), this);
connect(openAction, SIGNAL(triggered()), myLoader, SLOT(openSourceFile()));
menuTop->addAction(openAction);
//reload source file
reloadAction = new QAction(QIcon(":images/reload.png"), tr("&Reload"), this);
connect(openAction, SIGNAL(triggered()), myLoader, SLOT(reloadSourceFile()));
menuTop->addAction(reloadAction);
Note : after heavy debugging, I found that one function in the moc file of that class is being called after the execution of the catch block :
void Loader::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
Loader *_t = static_cast<Loader *>(_o);
switch (_id) {
case 0: _t->openSourceFile(); break;
case 1: _t->reloadSourceFile(); break;
default: ;
}
}
Q_UNUSED(_a);
}
it is called with _id = 1 which explain the undesired execution of the other slot. But why this happens ??? Does anybody could explain how this can be avoided ? I've already made my own application class derived from qApplication and override notify() but that does not change anything.
Should:
reloadAction = new QAction(QIcon(":images/reload.png"), tr("&Reload"), this);
connect(openAction, SIGNAL(triggered()), myLoader, SLOT(reloadSourceFile()));
menuTop->addAction(reloadAction);
be:
reloadAction = new QAction(QIcon(":images/reload.png"), tr("&Reload"), this);
connect(reloadAction, SIGNAL(triggered()), myLoader, SLOT(reloadSourceFile()));
// ^^^^^^^^^^^^
menuTop->addAction(reloadAction);
In my code I have additional thread for printing:
class PrintThread : public QThread {
public:
PrintThread(const QString& text, QPrinter* printer): mText(text), mPrinter(printer) {}
void run()
{
QTextDocument doc;
doc.setHtml(mText);
doc.print(mPrinter);
delete mPrinter;
}
private:
QString mText;
QPrinter *mPrinter;
};
Separate thread is needed to prevent GUI from freezing when printing to pdf.
Sometimes during printing I see such lines in console (many times repeated):
X Error: RenderBadGlyphSet (invalid GlyphSet parameter) 165
Extension: 148 (RENDER)
Minor opcode: 25 (RenderCompositeGlyphs32)
Resource id: 0×0
And any text in GUI disappears. What the problem and how to solve it? Thanks.
I'm using Qt 4.4.3
Thread is created here:
void MyClass::print() {
QPrinter *printer = new QPrinter;
printer->setOrientation(QPrinter::Landscape);
QPrintDialog dialog(printer);
if (dialog.exec() == QDialog::Accepted) {
QString text = dataForPrint();
mPrintThread = new PrintThread(text, printer);
connect(mPrintThread, SIGNAL(finished()), this, SLOT(onPrintingFinished()));
mPrintThread->start();
}
}