I am trying to use a Turkish translation file for my Qt project. I used Qt Linguist for generating the .ts file. The problem is when I load the translation file in my application, I am getting segmentation faults whenever I click on any item of QMenuBar.
I also have a context menu that is triggered with the contextMenuEvent of a GraphicsView in mainwindow. The program gives a segmentation fault when I try to execute the below line.
mContextMenu->exec(event->globalPos());
mContextMenu is a QMenu* and exec returns a QAction*. Basically I guess that when the translation belongs to a QAction this problem occurs. I saw the same problem when I translate the toolTips of toolButtons. How should I handle the translation of QActions and toolTips?
I am adding some actions to mContextMenu as below:
void RadarView::prepareMainMenu() {
mContextMenu = new QMenu();
//showLineAction->setShortcut(QKeySequence("Alt+Shift+L"));
mpStartRulerAction = new QAction(QObject::tr("Start Ruler"), this);
mContextMenu->addAction(mpStartRulerAction);
connect(mpStartRulerAction, SIGNAL(triggered()), this,
SLOT(menuStartRulerClicked()));
mpStartRulerAction->setProperty("TYPEVIEW", MV_StartRuler);
mpEndRulerAction = new QAction(QObject::tr("End Ruler"), this);
mContextMenu->addAction(mpEndRulerAction);
connect(mpEndRulerAction, SIGNAL(triggered()), this, SLOT(menuEndRulerClicked()));
mpEndRulerAction->setProperty("TYPEVIEW", MV_EndRuler);
mpCriticalRegionAction = new QAction(QObject::tr("Critical Region"), this);
mContextMenu->addAction(mpCriticalRegionAction);
connect(mpCriticalRegionAction, SIGNAL(triggered()), this, SLOT(menuDefineCriticalRegionClicked()));
mpCriticalRegionAction->setProperty("TYPEVIEW", MV_Critical_Region);
mpAScopeAction = new QAction(QObject::tr("A-Scope Line"), this);
mContextMenu->addAction(mpAScopeAction);
connect(mpAScopeAction, SIGNAL(triggered()), this, SLOT(menuAddAScopeLine()));
mpAScopeAction->setProperty("TYPEVIEW", MV_A_Scope);
}
Context Menu event of graphics view is implemented as below:
void RadarView::contextMenuEvent(QContextMenuEvent * event) {
LOGGER_START
//check if the item has its own context menu...
QList<QGraphicsItem*> items = this->items(event->pos());
if (items.size() != 0) {
bool isValid = true;
for (int i = 0; i < items.size(); ++i) {
QGraphicsRulerLineItem *rulerLineItem = NULL;
rulerLineItem = dynamic_cast<QGraphicsRulerLineItem*> (items[i]);
if (rulerLineItem != NULL || dynamic_cast<AScopeLineItem*> (items[i]) || dynamic_cast<PpiTargetItem*> (items[i])){
isValid = false;
}
else {
PpiPlotItem *targetItem = NULL;
targetItem = dynamic_cast<PpiPlotItem*> (items[i]);
if (targetItem != NULL) {
isValid = false;
if (currentVisibleMenuItems.contains(0)) {
startItem = targetItem;
} else if (currentVisibleMenuItems.contains(1)) {
endItem = targetItem;
}
}
}
}
if (isValid == true) {
if(currentVisibleMenuItems.size() ==0)
return;
//Get last clicked Position.
mLastClickedPos = event->pos();
//show menu of RadarView...
mpRightClickAction = mContextMenu->exec(event->globalPos());
} else {
QGraphicsView::contextMenuEvent(event);
}
}
LOGGER_END
}
The problem I described above is solved when I used QApplication instead of a customized class that inherits QApplication. Inside of the customized class, bool QApplication::notify ( QObject * receiver, QEvent * e ) function was implemented. When I used QApplication directly, all translations were loaded correctly and no problems ocuured regarding the QAction items and toolTips.
Related
I am trying to load images from a folder and view the previous and next images by clicking a button on the GUI (similar to Windows Image Viewer). The names of the images in this folder are xxxx_00.jpg to xxxx_99.jpg, so I use index++ and index-- to change the filename when clicking the buttons.
My codes work well for displaying the first image, but when I click a button to view the previous or the next images, it always shows
QPixmap::scaled: Pixmap is a null pixmap
and returns an empty image (the first image disappeared but new image didn't display).
Here's my code:
In mainwindow.cpp
void MainWindow::on_pushButton_4_clicked() //previous image
{
if (index < 1)
{
index = 99;
QLabel label;
label.setText("Go back");
label.show();
}
else
{
index--;
}
RefreshFilename();
loadimage();
}
void MainWindow::on_pushButton_5_clicked() //next image
{
if (index > 98)
{
index = 0;
QLabel label;
label.setText("ALL SET");
label.show();
}
else
{
index = index + 1;
}
RefreshFilename();
loadimage();
}
void MainWindow::loadimage()
{
// image.load(filename);
// im = image.scaled(500,500,Qt::KeepAspectRatio);
imageObject = new QImage();
imageObject->load(filename);
image = QPixmap::fromImage(*imageObject);
im = image.scaled(400,400,Qt::KeepAspectRatio);
scene = new QGraphicsScene(this);
scene->addPixmap(image);
scene->setSceneRect(image.rect());
ui->mainimage->setScene(scene);
}
I have spent 2 whole days on debugging this, but still have no idea. I am looking forward to any advice and support!
BTW The Refreshfilename Function works fine, so I did not paste it here.
Cause
Since I do not know what RefreshFilename(); does, I cannot tell exactly what the cause is.
However, I see a major flaw in your code, i.e. you create a new scene each time MainWindow::loadimage is called and this causes a memory leak.
When you provide more details I will be more specific here.
Solution
Set the scene once and add a QGraphicsPixmapItem to it, then in the loadImage update the pixmap of the item.
Keep the current number in a class attribute.
Again, I will be more specific once details are added.
Example
In any case (waiting for you to provide a MVCE), I have prepared a working example according to your task description:
#define IMAGE_COUNT 99
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
m_imgNum(0),
m_item(new QGraphicsPixmapItem())
{
auto *widget = new QWidget(this);
auto *layoutMain = new QVBoxLayout(widget);
auto *layoutButtons = new QHBoxLayout();
auto *btnPrev = new QPushButton(tr("Previous"), this);
auto *btnNext = new QPushButton(tr("Next"), this);
auto *view = new QGraphicsView(this);
view->setScene(new QGraphicsScene(this));
view->scene()->addItem(m_item);
layoutButtons->addStretch();
layoutButtons->addWidget(btnPrev);
layoutButtons->addWidget(btnNext);
layoutButtons->addStretch();
layoutMain->addWidget(view);
layoutMain->addLayout(layoutButtons);
setCentralWidget(widget);
resize(640, 480);
loadImage();
connect(btnPrev, &QPushButton::clicked, [this](){
if (m_imgNum > 0)
m_imgNum--;
else
m_imgNum = IMAGE_COUNT;
loadImage();
});
connect(btnNext, &QPushButton::clicked, [this](){
if (m_imgNum < IMAGE_COUNT)
m_imgNum++;
else
m_imgNum = 0;
loadImage();
});
}
void MainWindow::loadImage()
{
m_item->setPixmap(QString("images/image_%1.jpg").arg(m_imgNum, 2, 10, QChar('0')));
}
where m_imgNum, m_item and loadImage are declared in the header as:
private:
inline void loadImage();
int m_imgNum;
QGraphicsPixmapItem *m_item;
Recently I've met some problems about QT.As we have a lot of custom widgets (inherit from QT's basic widgets such as QWidget,QTreeWidget...),they worked fine at runtime,BUT,IT IS EASY TO CRASH when exiting program or destructing them,I don't know IF THERE ANYTHING WRONG or inappropriate while implementing a widget which inherits from a basic widget.
Here is an example:
ChatTreeWidget.cpp:
#include "ChatTreeWidget.h"
#include <QPicture>
#include <QDebug>
ChatTreeWidget::ChatTreeWidget(QWidget *parent)
:QTreeWidget(parent)
{
setRootIsDecorated(false);
setIndentation(0);
setHeaderHidden(true);
setIconSize(QSize(30, 30));
setFocusPolicy(Qt::NoFocus);
setObjectName(QString("chatTreeWidget"));
setStyleSheet("#chatTreeWidget{border:0px;}"
"QTreeWidget::item{border-bottom:1px solid #d9d9d9;padding-left:0px;}"
"QTreeWidget::item:hover{background-color: #def0ff;}"
"QTreeWidget::item:selected{background-color:#c2e2fd;}");
connect(this, &QTreeWidget::itemExpanded, this, [=](QTreeWidgetItem *item)
{
auto indexvar = item->data(0, Qt::UserRole).toInt();
indexvar -= 10000;
if (indexvar > m_iconList.size() || indexvar < 0)
return;
auto lbl = m_iconList.at(indexvar);
lbl->setPixmap(QPixmap(":/Widgets/Resources/chattree/sanjiao1.png"));
});
connect(this, &QTreeWidget::itemCollapsed, this, [=](QTreeWidgetItem *item)
{
auto indexvar = item->data(0, Qt::UserRole).toInt();
indexvar -= 10000;
if (indexvar > m_iconList.size() || indexvar < 0)
return;
auto lbl = m_iconList.at(indexvar);
lbl->setPixmap(QPixmap(":/Widgets/Resources/chattree/sanjiao2.png"));
});
connect(this, &QTreeWidget::itemClicked, this, [=](QTreeWidgetItem *item, int column) {
auto indexvar = item->data(0, Qt::UserRole).toInt();
indexvar -= 10000;
if (indexvar > m_iconList.size() || indexvar < 0)
return;
if (item->isExpanded())
{
setItemExpanded(item, false);
}
else
{
setItemExpanded(item, true);
}
});
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
}
ChatTreeWidget::~ChatTreeWidget()
{
qDebug() << "123123";
}
QTreeWidgetItem* ChatTreeWidget::addTreeWidgetTopItem(QString str)
{
return insertTreeWidgetTopItem(topLevelItemCount(), str);
}
QTreeWidgetItem* ChatTreeWidget::insertTreeWidgetTopItem(int index, QString str)
{
QWidget *widget = new QWidget(this);
QLabel *textLabel = new QLabel(widget);
QHBoxLayout *hlayout = new QHBoxLayout(widget);
QLabel *iconLabel = new QLabel(widget);
QSpacerItem *spacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
textLabel->setText(str);
textLabel->setStyleSheet(u8"font-family: \"Microsoft YaHei\"");
hlayout->addWidget(textLabel);
hlayout->addSpacerItem(spacer);
iconLabel->setPixmap(QPixmap(":/Widgets/Resources/chattree/sanjiao2.png"));
hlayout->addWidget(iconLabel);
hlayout->setContentsMargins(5, 0, 10, 0);
widget->setLayout(hlayout);
m_iconList.append(iconLabel);
QTreeWidgetItem *rootItem = new QTreeWidgetItem();
rootItem->setData(0, Qt::UserRole, m_index);
rootItem->setSizeHint(0, QSize(30, 30));
m_index++;
this->insertTopLevelItem(index, rootItem);
setItemWidget(rootItem, 0, widget);
rootItem->setBackground(0, Qt::green);
setExpandsOnDoubleClick(false);
return rootItem;
}
void ChatTreeWidget::setRootItemStyleSheet(QTreeWidgetItem *item,QString css)
{
auto widgets = itemWidget(item, 0);
widgets->setStyleSheet(css);
}
void ChatTreeWidget::setRootItemStyleSheet(QString css)
{
for (qint32 i = 0; i < topLevelItemCount(); i++)
{
auto rootItem = topLevelItem(i);
auto widgets = itemWidget(rootItem,0);
widgets->setStyleSheet(css);
}
}
this code is trying to implement a custom-treewidget to display chat members,so it inherits the QTreeWidget (once I thought I should implement it with QTreeView,but as I'm stupid and lazy,I used QTreeWidget Directly),and uses a special style-sheet to change display style.and as it's a public widget,it offers some interfaces to add top-level items.there is an example image:
when I destruct this widget (I' sure that this widget is token from UI or layout) and even sometimes QT's automatic destructing will cause a crash.It happens very frequently but not everytime.
the two main ways of destroying the widget are:
1.Add it to some Ui,and let it managed by that UI.
2.delete by hand:
chatTreeWidget->setParent(0);
chatTreeWidget->disconnect();
chatTreeWidget->deleteLater();
both of them can cause a random crash.
Is there anything wrong? or it's just a bug?
Thanks for any kind of help!
I have
QWidget *myWidget; //on my mainWindow with Qt Creator
and a
QComboBox *myComboBox;
When I change my selection of myComboBox, I would like to delete
myWidget->layout();
and set to myWidget another layout.
I'm doing : (with this help : https://stackoverflow.com/a/12034868/6105710)
void ConfWindow::on_comboBouton_currentIndexChanged(const QString &arg1)
{
if(ui->myWidget->layout()){
auto myLayout = ui->myWidget->layout();
QLayoutItem *item;
while((item = myLayout->takeAt(0)) != 0){
myLayout->removeItem(item);
delete item;
}
delete myLayout;
}
for(int i=0; i< someVector->size(); i++){
if( someVector->at(i)->getName() == arg1){
ui->myWidget->setLayout( someVector->at(i)->getLayout()); //which return a QHBoxLayout.
break;
}
}
}
and when I change my comboBox, It is painting my new layout, but my old layout still here..
I tried repaint(), update() etc...
Is it because I create layout in another class and add it with
auto myVector = new QVector<myClass>;
setLayout( myVector->getLayout() )
? I don't think so because I'm using pointer .. I don't understand ...
I know I can use the widget function of QTabWidget in order to get the the QPlanTextEdit from the specified tab. But how can I get the tab title text of the current tab widget?
QPlainTextEdit* pTextEdit = NULL;
QWidget* pWidget= ui->tabWidget->widget(1);
if (pWidget->metaObject()->className() == "QPlainTextEdit")
pTextEdit = (QPlainTextEdit*)pWidget;
else
{
QList<QPlainTextEdit *> allTextEdits = pWidget->findChildren<QPlainTextEdit *>();
if (allTextEdits.count() != 1)
{
qError() << "Error";
return;
}
pTextEdit = allTextEdits[0];
}
ptextEdit->setPlainText("Updated Plain Text Edit);
// HERE I NEED THE CURRENT TAB'S TEXT!!
int index = ui->tabWidget->currentIndex();
QString currentTabText = ui->tabWidget->tabText(index);
I'm working on a project where i'm trying to add a QPushButton into a QTableView.
also i want to connect that button to open a document from a database. So far i added the button and i wrote the connect statement for it but when i click on the button nothing happened.
here is my code
void MainWindow::DocumentTable()
{
tableview = new QTableView;
query = new QSqlQueryModel(this);
signalMapper = new QSignalMapper(this);
foreach(it,treeWidget->selectedItems())
{
for (int col=0; col< it->columnCount(); ++col)
{
qDebug() << col << it->text(col);
QSqlQuery qry;
qry.prepare("select * from document where Folno=:Folno");
qry.bindValue(":Folno", it->text(col));
qry.exec();
query->setQuery(qry);
tableview->setModel(query);
tableview->setEditTriggers(QAbstractItemView::NoEditTriggers);
for (int i = 0; i< 1000; i++)
{
button= new QPushButton("Open Document");
tableview->setIndexWidget(tableview->model()->index(i, 0), button);
signalMapper->setMapping(button, i);
}
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(imageFROMdatabase()));
tableview->show();
Docwidget= new QDockWidget(this);
Docwidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
Docwidget->setWidget(tableview);
addDockWidget(Qt::RightDockWidgetArea,Docwidget);
Docwidget->show();
if(!query->submit())
{
QMessageBox::warning(0,"Error",query->lastError().text());
}
db.close();
}
}
}
and this is the slot function
void MainWindow::imageFROMdatabase()
{
QSqlQuery imageQuery;
imageQuery.prepare("SELECT * from doc_page where doc_no=:doc_no and f_number=:f_number");
imageQuery.bindValue(":doc_no", 1);
imageQuery.bindValue(":f_number",1);
imageQuery.exec();
imageQuery.next();
if( imageQuery.lastError().isValid())
{
QMessageBox::warning(0,"Error",imageQuery.lastError().text());
// QSqlDatabase::database().rollback();
}
else
{
// QByteArray ba1 = imageQuery.value(1).toByteArray();
QPixmap pic;
pic.loadFromData( ba);
scrollArea = new QScrollArea;
scrollArea->setBackgroundRole(QPalette::Dark);
scrollArea->setEnabled(true);
QString fileName = QFileDialog::getOpenFileName(this,"Open Image File",QDir::currentPath());
QImage image(fileName);
scene = new QGraphicsScene();
view = new QGraphicsView(scene);
item = new QGraphicsPixmapItem(QPixmap::fromImage(image));
scene->addItem(item);
xwidget= new QDockWidget(this);
xwidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
xwidget->setWidget(view);
addDockWidget(Qt::RightDockWidgetArea,xwidget);
xwidget->show();
db.close();
}
}
please tell if anything wrong in these codes.
The slot method is not same as signal method. They should have exact equal signatures. qDebug() should have generated some warnings for you. Read outputs carefully. imageFROMDatabase() method should accept an integer as its input too. Signals are not real functions. They are used to trigger another function which is matched in signature with them.
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(imageFROMdatabase()));
Change it like this :
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(imageFROMdatabase(int)));
ans also :
void MainWindow::imageFROMdatabase( int x ) { ... }
Also if the signals and slots are not in a thread read the manual enum Qt::ConnectionType