Resize the button widget in QFileDialog layout - qt

How to change the size of a button in the QFileDialog? I tried the below code; it compiles but the application exits unexpectedly if I try to load the file dialogue.
Please let me know what is going wrong. I am new to QT. :(
QFileDialog *fdiag = new QFileDialog();
QGridLayout *glayout = static_cast <QGridLayout*>(fdiag->layout());
QLayoutItem *li = glayout->itemAtPosition(3,3);
QRect buttonRect = li->geometry() ;
int newHeight = buttonRect.height() + 20;
int newWidth = buttonRect.height() + 20;
buttonRect.setHeight(newHeight);
buttonRect.setWidth(newWidth);
li->setGeometry(buttonRect);
fdiag->resize(720,480);
fdiag->setWindowTitle("Media Folder");
fdiag->exec();

You could just use a stylesheet:
QFileDialog *fdiag = new QFileDialog;
fdiag->setStyleSheet("QPushButton{min-height: 40px; min-width: 200px;}");
Or if you want to resize a specific button only:
QDialogButtonBox *box = fdiag->findChild<QDialogButtonBox*>();
if(box)
{
QPushButton *button = box->button(QDialogButtonBox::Open);
if(button)
{
button->setMinimumHeight(40);
button->setMinimumWidth(200);
}
}

As i've got this problem recently, with Qt5 - for some reasons in Qt4 it worked - you need to make sure, that Qt returns not Null from layout().
You need to initialize the System dialog with the Option QFileDialog::DontUseNativeDialog, e.g. with dlg->setOption(QFileDialog::DontUseNativeDialog, true);

Related

Adding Rows in a QTreeWidget in runtime messes up widgetItems visuals

I have a QDialog show a QTreeWidget that has the parameters of some objects.
I have added a button to add extra fields in the vectors of the objects visually like this.
void on_Create_Surface_Pressed()
{
QPushButton * const button = qobject_cast<QPushButton*>(sender());
QTreeWidgetItem* branch = treeButtons[button];
if(branch)
{
QTreeWidgetItem* leaf = new QTreeWidgetItem(branch);
QString str("Point ");
str+=QString::number(branch->childCount()-1);
QLabel* label = new QLabel(str);
QString surfType[3] = {QString("x") , QString("y") ,QString("z")};
QTableWidget* surfTable = sampleTree( surfType);<--(Create and add a
Table under the
qtreewidgetItem)
leaf->treeWidget()->setItemWidget(leaf , 0 , label);
leaf->treeWidget()->setItemWidget(leaf , 1 , surfTable);
update();
}
}
My problem is that the new rows are rendered above the next QTreeWidgetItem until the user collapses the tree(which is the gimmick i m using).
Is there a workaround for this? Or isn't QTreeWidget purposed for this use and a QTreeView would serve better?

How to embed a QML view into a native window

I'm having a problem trying to insert a QML view into a native OSX window. I know it's possible, but I don't know what I'm doing wrong.
Basically, my goal is, given a native NSView* to then embed a QML based widget. The problem is that I get it to point where it does indeed renderer the qml inside the view but it creates an extra transparent window to the side and it doesn't seem to redraw the QML view properly.
Here's the code that I'm using (please disregard all the memory leaks):
#interface AppDelegate ()
-(void)processEvents;
#property(nonatomic) NSTimer* timer;
#property(nonatomic) QApplication* qt;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
NSWindow* window = [[[NSApplication sharedApplication] windows] objectAtIndex:0];
NSView *view = [window contentView];
assert(view);
char* test[0];
int count = 0;
QApplication::instance()->setAttribute(Qt::AA_MacPluginApplication);
_qt = new QApplication(count, test);
QMacNativeWidget* native = new QMacNativeWidget(view);
assert(native);
QQuickWidget* qml = new QQuickWidget(native);
qml->setSource(QUrl(QStringLiteral("main.qml")));
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(qml);
native->setLayout(layout);
qml->show();
native->show();
NSView* qmlView = (NSView*)native->winId();
[view addSubview:qmlView];
_timer = [NSTimer scheduledTimerWithTimeInterval:0.03 target:self selector:#selector(processEvents) userInfo:nil repeats:YES];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification
{
// Insert code here to tear down your application
[_timer invalidate];
_qt->quit();
}
-(void)processEvents
{
_qt->processEvents();
_qt->sendPostedEvents(0,-1);
}
#end
And here's the simple qml:
import QtQuick 2.7
Item
{
visible: true
x: 0;
y: 0;
width: 100
height: 100
Rectangle
{
anchors.fill: parent
color: 'blue'
MouseArea
{
anchors.fill: parent
onClicked:
{
console.log(parent.color);
if(parent.color == '#0000ff')
parent.color = 'green';
else
parent.color = 'blue';
}
}
}
}
QQuickWidget composities its content with other widget content in a slightly complex way, involving a framebuffer and offscreen window, which I suspect might explain the odd results you see - I would not expect it to work in a plugin situation.
The easiest option would be use a QQuickWindow (or QQuickView) with createWindowContainer to turn the QWindow into a QWidget you can parent to your QMacNativeWidget.
However, I think the most robust approach would be to ignore widgets and windows entirely, and integrate at the framebuffer level, using QQuickRenderControl and an NSOpenGLView. This is more work to code up but keeps the NSView hierarchy straightforward, and should give the best possible performance. You can either render directly into the native OpenGL view (which requires creating a QOpenGLContext from the native context, possible since Qt 5.4), or into a framebuffer using a texture shared between the QtQuick and NSOpenGLContext.

Hide QLineEdit blinking cursor

I am working on QT v5.2
I need to hide the blinking cursor (caret) of QLineEdit permanently.
But at the same time, I want the QLineEdit to be editable (so readOnly and/or setting editable false is not an option for me).
I am already changing the Background color of the QLineEdit when it is in focus, so I will know which QLineEdit widget is getting edited.
For my requirement, cursor (the blinking text cursor) display should not be there.
I have tried styleSheets, but I can't get the cursor hidden ( {color:transparent; text-shadow:0px 0px 0px black;} )
Can someone please let me know how can I achieve this?
There is no standard way to do that, but you can use setReadOnly method which hides the cursor. When you call this method it disables processing of keys so you'll need to force it.
Inherit from QLineEdit and reimplement keyPressEvent.
LineEdit::LineEdit(QWidget* parent)
: QLineEdit(parent)
{
setReadOnly(true);
}
void LineEdit::keyPressEvent(QKeyEvent* e)
{
setReadOnly(false);
__super::keyPressEvent(e);
setReadOnly(true);
}
As a workaround you can create a single line QTextEdit and set the width of the cursor to zero by setCursorWidth.
For a single line QTextEdit you should subclass QTextEdit and do the following:
Disable word wrap.
Disable the scroll bars (AlwaysOff).
setTabChangesFocus(true).
Set the sizePolicy to (QSizePolicy::Expanding, QSizePolicy::Fixed)
Reimplement keyPressEvent() to ignore the event when Enter/Return is hit
Reimplement sizeHint to return size depending on the font.
The implementation is :
#include <QTextEdit>
#include <QKeyEvent>
#include <QStyleOption>
#include <QApplication>
class TextEdit : public QTextEdit
{
public:
TextEdit()
{
setTabChangesFocus(true);
setWordWrapMode(QTextOption::NoWrap);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
setFixedHeight(sizeHint().height());
}
void keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
event->ignore();
else
QTextEdit::keyPressEvent(event);
}
QSize sizeHint() const
{
QFontMetrics fm(font());
int h = qMax(fm.height(), 14) + 4;
int w = fm.width(QLatin1Char('x')) * 17 + 4;
QStyleOptionFrameV2 opt;
opt.initFrom(this);
return (style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(w, h).
expandedTo(QApplication::globalStrut()), this));
}
};
Now you can create an instance of TextEdit and set the cursor width to zero :
textEdit->setCursorWidth(0);
Most straight forward thing I found was stolen from this github repo:
https://github.com/igogo/qt5noblink/blob/master/qt5noblink.cpp
Basically you just want to disable the internal "blink timer" Qt thinks is somehow good UX (hint blinking cursors never were good UX and never will be - maybe try color or highlighting there eh design peeps).
So the code is pretty simple:
from PyQt5 import QtGui
app = QtGui.QApplication.instance()
app.setCursorFlashTime(0)
voilĂ .
Solution in python:
# somelibraries
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.setFocus() # this is what you need!!!
container = QWidget()
container.setLayout(self.layout)
# Set the central widget of the Window.
self.setCentralWidget(container)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
I ran into the same problem but setReadOnly is not a viable option because it alters the UI behavior in other places too.
Somewhere in a Qt-forum I found the following solution that actually solves the problem exactly where it occurs without having impact on other parts.
In the first step you need to derive from QProxyStyle and overwrite the pixelMetric member function:
class CustomLineEditProxyStyle : public QProxyStyle
{
public:
virtual int pixelMetric(PixelMetric metric, const QStyleOption* option = 0, const QWidget* widget = 0) const
{
if (metric == QStyle::PM_TextCursorWidth)
return 0;
return QProxyStyle::pixelMetric(metric, option, widget);
}
};
The custom function simply handles QStyle::PM_TextCursorWidth and forwards otherwise.
In your custom LineEdit class constructor you can then use the new Style like this:
m_pCustomLineEditStyle = new CustomLineEditProxyStyle();
setStyle(m_pCustomLineEditStyle);
And don't forget to delete it in the destructor since the ownership of the style is not transferred (see documentation). You can, of course, hand the style form outside to your LineEdit instance if you wish.
Don't get complicated:
In QtDesigner ,
1.Go the the lineEdit 's property tab
2.Change focusPolicy to ClickFocus
That's it...

Dynamically create context menu in QT associated to a toolbutton

In my application I have a QToolButton related to the presence of an USB Pen Drive. When the Pen drive is inserted I would like to show the QToolButton and create a context menu associated to the content of the pen drive.I have a different menu dynamically created to be assigned to the Button.
My code works well for the first time, but when I create a new menu it doesn't appear.
In this last version of code, when I show the button for the second time I get the the previous menu (Dismount is the only item present) and when i click on the item it doesn't do anything.
EDIT: If I use the QAction instead of the QWidgetAction the code works fine. So it seems something related to the QWidgetAction of QLabel used inside of it.
The following is a simplified version of my code:
/* member variables */
QMenu *m_pqmConMenUSB;
QLabel m_MenuItem;
/* costructor */
ui->tbDriveUSB->setContextMenuPolicy(Qt::CustomContextMenu);
m_pqmConMenUSB = NULL;
QObject::connect(ui->tbDriveUSB, SIGNAL(customContextMenuRequested(const QPoint&)),this, SLOT(showUSBCM(const QPoint&)));
m_MenuItem.setStyleSheet("QLabel { background-color : black; color : white; }");
m_MenuItem.setText("Dismount");
QFont fonte = m_MenuItem.font();
fonte.setPixelSize(16);
m_MenuItem.setFont(fonte);
QPalette ChePalette = m_MenuItem.palette();
m_MenuItem.setMinimumSize(0,32);
ChePalette.setColor(m_MenuItem.backgroundRole(), Qt::black);
ChePalette.setColor(m_MenuItem.foregroundRole(), Qt::white);
m_MenuItem.setPalette(ChePalette);
/*member functions*/
void MainWindow::showUSBCM(const QPoint& pos)
{
// copied from an example
if (pos != QPoint(0,0)) {
// Execute context menu
if (m_pqmConMenUSB!=NULL) m_pqmConMenUSB->exec(pos);
}
}
void MainWindow::OnUSBMounted()
{
/* this static boolean is used to simulate a change in the menu content */
static bool tryToChange = false;
ui->tbDriveUSB->show();
m_pqmConMenUSB = new QMenu(this);
QWidgetAction *menuItemW = new QWidgetAction(this);
menuItemW->setDefaultWidget(&m_MenuItem);
menuItemW->setText("Dismount");
connect(menuItemW,SIGNAL(triggered()), this, SLOT(DoDismount()));
m_pqmConMenUSB->addAction(menuItemW);
if (tryToChange)
{
menuItemW = new QWidgetAction(this);
menuItemW->setDefaultWidget(&m_MenuItem);
menuItemW->setText("Update");
connect(menuItemW,SIGNAL(triggered()), this, SLOT(Update()));
m_pqmConMenUSB->addAction(menuItemW);
}
tryToChange = !tryToChange;
ui->tbDriveUSB->setMenu(m_pqmConMenUSB);
}
void MainWindow::OnUSBDismounted()
{
ui->tbDriveUSB->hide();
/* the first version of the code tries to destroy the menu with the following code, but it doesn't work
/*ui->tbDriveUSB->setMenu(NULL);
QAction *pAction;
foreach (pAction, m_pqmConMenUSB->actions())
pAction->disconnect(this);
delete(m_pqmConMenUSB);
m_pqmConMenUSB = NULL;*/
}
A useful pattern to dynamically populate a menu associated with a QToolButton is to first create the menu and attach it to the button, but do not populate it. Then connect a slot to the QMenu::aboutToShow() signal. In the slot implementation, clear the contents of the menu and populate it as needed for the current state of the application.
As I mentioned yesterday, the problem was related to QLabels. In my code I used two member variables of QLabel type. The QLabels weren't pointers.
When I delete the action, the QLabels weren't able to show them again. I suppose it was related to the removeAction(d->menuAction); function which destroys QWidget associated to the QWidgetAction. That function was called when the ui->tbDriveUSB->setMenu(NULL); was called.
I choose to use the QLabel just for stylesheet and size, but it's possibile to set that properties in the menu. This is enough for me.
I think that, making a new QLabel when the QWidgetAction is created and delete it when the QWidgetAction is deleted, could make works the previous code. I haven't tested it.
In order to complete the answer, the following is my current code that works well
/* member variable */
QMenu *m_pqmConMenUSB;
/* constructor */
ui->tbDriveUSB->setContextMenuPolicy(Qt::CustomContextMenu);
QObject::connect(ui->tbDriveUSB, SIGNAL(customContextMenuRequested(const QPoint&)),this, SLOT(showUSBCM(const QPoint&)));
m_pqmConMenUSB = new QMenu(this);
QFont fonte = m_pqmConMenUSB->font();
fonte.setPixelSize(16);
m_pqmConMenUSB->setFont(fonte);
m_pqmConMenUSB->setStyleSheet("QMenu { background-color : black; color : white; }");
m_pqmConMenUSB->setMinimumSize(0,32);
/*member functions*/
void MainWindow::showUSBCM(const QPoint& pos)
{
if (pos != QPoint(0,0))
{
// Execute context menu
if (m_pqmConMenUSB!=NULL) m_pqmConMenUSB->exec(pos);
}
}
void MainWindow::OnUSBMounted()
{
static bool tryToChange = true;
ui->tbDriveUSB->show();
QAction *menuItem = new QAction("Dismount",this);
connect(menuItem,SIGNAL(triggered()), this, SLOT(DoDismount()));
m_pqmConMenUSB->addAction(menuItem);
if (tryToChange)
{
QAction *menuItem2 = new QAction("upDate",this);
connect(menuItem2,SIGNAL(triggered()), this, SLOT(Update()));
m_pqmConMenUSB->addAction(menuItem2);
}
tryToChange = !tryToChange;
ui->tbDriveUSB->setMenu(m_pqmConMenUSB);
}
void MainWindow::OnUSBDismounted()
{
printf("SEI UNO SMONTATO\n\r");
ui->tbDriveUSB->setMenu(NULL);
QAction *pAction;
foreach (pAction, m_pqmConMenUSB->actions())
{
pAction->disconnect(this); // receiver
delete pAction;
}
ui->tbDriveUSB->hide();
m_pqmConMenUSB->clear();
}

in qt how to make a button move accordingly when resizing a widget

I wanna do this: When I enlarge my mainwindow pressing and moving mouse, I want the widget(like a button) to move accordingly(not resize the button) to make sure the button is always at the edge of my mainwindow. I can do it in this way:
void MainWindow::resizeEvent(QResizeEvent *e)
{
int x,y,newx,newy,resizex,resizey;
newx = this->width();
newy = this->height();
resizex = newx - mainwindowWidth;
resizey = newy - mainwindowHeight;
x = ui->button->pos().x();
y = ui->button->pos().y();
ui->button->move(x+resizex, y+resizey);
mainwindowWidth = newx;
mainwindowHeight = newy;
}
But it's so complex. Does QPushButton have any attribute to do this job easily? Waiting for your answer. Any advice would be helpful. Thanks in advance.
You can add your pushbutton to a layout and add spacers to push the button to the edge.
Heres an example:
QHBoxLayout *hlayout = new QHBoxLayout;
ui->verticalLayout->addLayout(hlayout);
QPushButton *button = new QPushButton("Button");
hlayout->addWidget(button);
QSpacerItem *item = new QSpacerItem(1,1, QSizePolicy::Expanding, QSizePolicy::Fixed);
hlayout->addSpacerItem(item);

Resources