I have a dialog where user selects file(s). I added QCompleter to the line edit, which automatically suggests next file name:
However if user clicks on file, the suggestions disappear:
I want them to reappear if directory is selected and display the files in that directory. I tried to do this inside the QLineEdit::textChanged signal. I connected it to such slot:
void ImportFromExcelDialog::pathChanged( const QString& path )
if(path.length()>0) {
QFileInfo info(path);
if( info.exists() && info.isFile() && info.isReadable() ) {
// File selected, do stuff with it
}
else {
// If a directory
if((info.exists() && info.isDir())) {
if(!path.endsWith("/"))
ui->fileLineEdit->setText(path + "/");
// Assume QCompleter* completer_; which is set in constructor
if(completer_!=nullptr)
completer_->complete();
}
}
}
}
The problem is that calling complete() shows the old list of files, the one for parent directory:
I can click telemetrie as many times as I want and the display won't change.
So how to force QCompleter to reappear and handle the new value of the text field?
Related
I'm having a problem closing my JavaFX application. The application keeps running in the background even after closing. I think the actual problem is caused due to the alert box which will popup while closing the application for confirmation, if the alert doesn't pop up (on certain conditions) then the application exits normally.
Actually, I want the user to confirm whether to save the file or not before closing the application so I have added an alert box that will show only if the file is not saved manually (using Ctrl+S or File->Save option) before closing the application. When the popup appears, if the user selects to save the file it will save as usual if it chooses to cancel then the application continues to run.
But the problem is that if the alert box appears for confirmation and the user chooses to save or don't save option then the application doesn't close completely (even after completing all the task related to saving if the user chooses to save the file) it only hides the stage and keeps running in the background but if the alert box doesn't appear for confirmation then the application closes normally.
Here is the code for widow.setOnCloseRequest(); event:-
Platform.runLater(() -> {
window = App.getStage();
window.setOnCloseRequest(event -> {
if (!saveIfFileEdited()) {
event.consume();
} else {
scheduledService.shutdown();
// Platform.exit(); //I have tried this also but it dosen't work.
}
});
});
Here it will call the saveIfFileEdited() method which will handle the alert popup for confirmation & and here is its code:-
private boolean saveIfFileEdited() {
if (isEdited.get()) { // this will check if the file was edited but not saved.
Alert fileEditedAlert = new Alert(Alert.AlertType.CONFIRMATION);
fileEditedAlert.setTitle("Notepad");
fileEditedAlert.setHeaderText(null);
fileEditedAlert.setContentText("Do you want to save the changes to " + windowTitle.get() + "?");
ButtonType save = new ButtonType("Save");
ButtonType dontSave = new ButtonType("Don't Save");
fileEditedAlert.getButtonTypes().setAll(save, dontSave, ButtonType.CANCEL);
Optional<ButtonType> result = fileEditedAlert.showAndWait();
if (result.isPresent() && result.get().equals(save)) {
handleSaveFile(null); // this func will save the file, it may open save file dialog if the file is going to be saved for first time.
return true;
} else if (result.isPresent() && result.get().equals(dontSave)) {
return true;
} else if (result.isPresent() && result.get().equals(ButtonType.CANCEL)) {
return false;
} else {
return false;
}
} else {
return true;
}
}
Please help me to resolve this issue.
I cannot close the JVM forcefully using System.exit(0); because there may be some task in another thread which has to be completed even after closing the application.
Thanks.
How do I recognize a double click on a tab in order to change its label?
Preferrably I could edit the label in place but alternatively I could also get a string from another input box. Any suggestions?
The tab gets added and the label specified currently like:
QString tab_label = QString("Shell (") + QString::number(session->id(), 16) + ")";
addTab(session->widget(), tab_label);
and I'd want to be able to edit the label after creation.
Oh and I should mention here that I'm a Qt newbie, too!
EDIT1
full method:
int SessionStack::addSession(Session::SessionType type)
{
Session* session = new Session(type, this);
connect(session, SIGNAL(titleChanged(int,QString)), this, SIGNAL(titleChanged(int,QString)));
connect(session, SIGNAL(terminalManuallyActivated(Terminal*)), this, SLOT(handleManualTerminalActivation(Terminal*)));
connect(session, SIGNAL(activityDetected(Terminal*)), m_window, SLOT(handleTerminalActivity(Terminal*)));
connect(session, SIGNAL(silenceDetected(Terminal*)), m_window, SLOT(handleTerminalSilence(Terminal*)));
connect(session, SIGNAL(destroyed(int)), this, SLOT(cleanup(int)));
m_sessions.insert(session->id(), session);
QString tab_label = QString("Shell (") + QString::number(session->id(), 16) + ")";
addTab(session->widget(), tab_label);
emit sessionAdded(session->id());
raiseSession(session->id());
return session->id();
}
There's a QTabBar::tabBarDoubleClicked signal, you just need to connect it to a slot to detect a double click. Also you'll need some widget to actually edit the tab's text. If you want it "out of place" (say, you open a dialog) then it should be enough to do something like:
connect(tabWidget->tabBar(), &QTabBar::tabBarDoubleClicked,
this, MyWidget::editTabBarLabel);
void MyWidget::editTabBarLabel(int tabIndex)
{
if (tabIndex < 0)
return;
// open dialog asking for the new label,
// f.i. via QInputDialog::getText
// set the new label bakc
}
If instead you want some in-place modification you'll need to more or less heavily modify QTabBar to do so.
The simplest option would be opening a QLineEdit on the right tab. To get the geometry of a tab via QTabBar:.tabrect, so that you can place the line edit in the same geometry. You'll very likely fall short on that path (see below) and you'll need to subclass QTabBar and use initStyleOption for the given tab, then set the lineedit's geometry to the right subrect (for instance, do not cover the "side widgets" of a tab).
Random pseudo braindumped code:
void MyTabBar::editTabBarLabel(int tabIndex)
{
if (tabIndex < 0)
return;
if (!m_lineEdit) {
m_lineEdit = new QLineEdit(this);
// once done, commit the change, or abort it, anyhow
// destroy/hide (?) the line edit
connect(m_lineEdit, &QLineEdit::editingFinished,
this, &MyTabBar::renameLabel);
} else {
// we're actually editing something else, what to do?
// commit the other change and start editing here?
}
m_editedTabIndex = tabIndex; // remember which one we're editing
m_lineEdit->setText(tabText(tabIndex));
// not "entirely" accurate, you need better subrect control here,
// cf. QStyle and https://doc.qt.io/qt-5/style-reference.html#widget-walkthrough
// that's why this should really be a QTabBar subclass, because
// you'll need to invoke initStyleOption and then fetch the subrects from the style
m_lineEdit->setGeometry(tabRect(tabIndex));
m_lineEdit->show();
}
// also track resize of the tabbar, relayout, tab reorder, tab insertion and removal, etc.
// move the QLineEdit accordingly
I have a Qt application that loads some file after clicking on button. I am using QFileDialog to open files. Every time I close file dialog, the application main window (QMainWindow) is behind all other opened windows (internet browser, explorer etc.). Is this standard behaviour? And is there any way to prevent this? I tried
// set always on top window
Qt::WindowFlags flags = this->windowFlags();
this->setWindowFlags(flags | Qt::WindowStaysOnTopHint);
but it causes that also file dialog is behind main window.
Edited:
Here is fragment of code to call file dialog (method that calls it is static method of my class LoadData):
void MainWindow::on_buttonIP_clicked()
{
loaded = LoadData::OpenFiles(IPFiles);
}
bool LoadData::openFiles(QStringList &fileNames)
{
// open files dialog
fileNames = QFileDialog::getOpenFileNames(0,
tr("Open files"), "", "Text Files (*.txt *.dat *.points)");
if (fileNames.isEmpty())
{
return false;
}
return true;
}
First argument of QFileDialog::getOpenFileNames must not be nullptr. Set it to your main window, and everything will be OK.
I have a QToolButton with an attached QMenu which includes a couple of QActions.
One of those actions is the button's default action. The default action dynamically changes when clicking on the actions and this works great.
Now, these QActions get enabled and disabled by signals. When exactly the (current) default action get's disabled, the QToolButton gets disabled, too.
This results in an inaccessible QMenu which still contains enabled QMenu entries (QActions) that I want to be able to select.
So: Can I somehow still make the Menu available when the default action is getting a setEnabled(false)? Or are there some other Ideas?
I did the following to exactly resolve the issue as described:
In my QToolButton class I override eventFilter as follows:
bool MultiToolButton::eventFilter( QObject* inObject, QEvent* inEvent )
{
MultiToolButton* _multiToolButton =
dynamic_cast<MultiToolButton*>(inObject);
QMouseEvent* _mouseEvent = dynamic_cast<QMouseEvent*>(inEvent);
if(_multiToolButton
&& _mouseEvent && _mouseEvent->type() == QEvent::MouseButtonPress)
{
mMenu.setEnabled(true);
showMenu();
return true;
}
return QToolButton::eventFilter(inObject, inEvent);
}
and add the following line to the contructor:
installEventFilter(this);
Thank you for your answer nonetheless. However, I didn't check it.
Naively what you can do is to write a small function that you call whenever you disable a QAction to see if it is the current default action with somethinglike this:
void MyDialog::on_button_clicked()
{
action2->setEnabled( false );
checkForDefault(action2);
}
void MyDialog::checkForDefault(QAction *action)
{
if ( tButton->defaultAction() == action ) {
QList<QAction*> list = tButton->menu()->actions();
int index = list.indexOf(action);
QAction *newDefault = list.at( ( index+1 ) % list.count() );
tButton->setDefaultAction(newDefault);
tButton->setEnabled(true);
}
}
This will check if the action that was changed is the current default action of the button and if so will select the next QAction within the QMenu as the new default (or the first action if the disabled action is the last in the list).
A different way would probably be to have your own class inheriting from QToolButton and to overload its actionEvent ( QActionEvent * event ) method to perform what you need.
Is this of any help?
The problem of the arrow being disabled can be solved by the following stylesheet, which replaces the standard arrow with an image located in url path_to_arrow. This image does not changed when the button is disabled :
QToolButton::menu-indicator,::menu-button
{
}
QToolButton::menu-arrow
{
image: url("path_to_arrow");
}
I'm writing a program using Qt 4.8 that displays a table (QTableWidget) filled with filenames and file's params. First an user adds files to the list and then clicks process. The code itself updates the contents of the table with simple progress description. I want the table by default to be scrolled automatically to show the last processed file and that code is ready.
If I want to scroll it by hand the widget is being scrolled automatically as soon as something changes moving the viewport to the last element. I want to be able to override the automated scroll if I detect that it was the user who wanted to change view.
This behavior can be seen in many terminal emulator programs. When there's a new line added the view is scrolled but when user forces the terminal to see some previous lines the terminal does not try to scroll down.
How could I do that?
Solution:
I created an object which filters event processed by my QTableWidget and QScrollBar embedded inside. If I spot the event that should turn off automatic scrolling I just set a flag and stop scrolling view if that flag is set.
Everything is implemented inside tableController class. Here are parts of three crucial methods.
bool tableController::eventFilter(QObject* object, QEvent* event)
{
switch (event->type())
{
case QEvent::KeyPress:
case QEvent::KeyRelease:
case QEvent::Wheel:
case QEvent::MouseButtonDblClick:
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
_autoScrollEnabled = false;
default:
break;
}
return QObject::eventFilter(object, event);
}
void tableController::changeFile(int idx)
{
[...]
if (_autoScrollEnabled)
{
QTableWidgetItem* s = _table.item(_engine.getLastProcessed(), 1);
_table.scrollToItem(s);
}
[...]
}
void tableController::tableController()
{
[...]
_autoScrollEnabled = true;
_table.installEventFilter(this);
_table.verticalTableScrollbar()->installEventFilter(this);
[...]
}
Thanks for all the help. I hope somebody will find it useful :)
Subclass QTableWidget and overload its wheelEvent. You can use the parameters of the supplied QWheelEvent object in order to determine if the user scrolled up or down.
Then use a simple boolean flag which is set (or reset) in your wheelEvent override. The method which is responsible for calling scrollToBottom() should then consider this boolean flag.
You will have to find a way to figure out when to set or reset that flag, e.g. always set it when the user scrolls up and reset it when the user scrolls down and the currently displayed area is at the bottom.
connect(_table->view()->verticalScrollBar(), &QAbstractSlider::actionTriggered, this, [this](int) {
_autoScrollEnabled = false;
});