I'm trying to make drag and drop inside a tree widget work to be able to move items around inside that widget. I've managed to make items draggable but when I release the mouse button the item disappears. To narrow it down I've tried the following example (taken from another post here on SO) which has the same issues as my tree widget in Qt 5.4 on Windows 7:
#include <QListWidget>
int main(int argc, char **argv)
{
QApplication a(argc, argv);
QListWidget lw;
for(int i = 1; i < 10; ++i)
lw.addItem(new QListWidgetItem(QString("Item %1").arg(i)));
lw.setDragEnabled(true); // ***
lw.viewport()->setAcceptDrops(true); // ***
lw.setDefaultDropAction(Qt::MoveAction); // ***
lw.setDropIndicatorShown(true); // ***
lw.setDragDropMode(QAbstractItemView::InternalMove);
lw.show();
a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()));
a.exec();
}
When I run this code and drag/drop some items it looks like this:
Why is the dragged item removed? Any ideas of what I'm missing?
I have changed one line in your code:
lw.setDefaultDropAction(Qt::TargetMoveAction);
and now it works fine (Qt 5.4.1 Windows 8, Visual Studio 2013).
It's a bug in Qt 5.4.1, your code work correctly on Qt 4.8.6
With Qt 5.10 or later, you have to call "setMovement(QListView::Free)"
myList->setDragDropMode(QAbstractItemView::InternalMove);
myList->setDefaultDropAction(Qt::TargetMoveAction);
#if QT_VERSION >= QT_VERSION_CHECK(5,10,0)
myList->setMovement(QListView::Free);
#endif
Related
I have a Qt application for Windows which contains a list of files in a widget. I want to be able to drag the files from this widget to another application. I am using Qt-base drag and drop mechanism and it works well in most cases. One case which does not work is to drag and drop it into MS Edge browser, for example when I open MS Edge and start writing an email with mail.google.com and I want to add the files as attachment by drag and drop from my Qt application. It is strange that this does work in Chrome, Firefox and also in ancient Internet Explorer. But not in Edge. Here is my minimalistic example. Try to drag files from the widget to a web page which accepts drag and drop of a file. On my computer this works for all browsers except Edge.
#include <QApplication>
#include <QDrag>
#include <QLabel>
#include <QMimeData>
#include <QMouseEvent>
class Window : public QLabel
{
public:
void mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
QList<QUrl> urls;
urls.append(QUrl::fromLocalFile("C:/test/test1"));
urls.append(QUrl::fromLocalFile("C:/test/test2"));
QMimeData* mimeData = new QMimeData();
mimeData->setUrls(urls);
QDrag* drag = new QDrag(this);
drag->setMimeData(mimeData);
drag->exec(Qt::CopyAction);
}
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.setText("Drag from here...");
w.show();
return a.exec();
}
Note that I am passing data as text/uri-list MIME type. I was observing how other applications behave as drag source, and they seem to work fine - e.g. when dragging from File Explorer, Total Commander etc to MS Edge. When I look at the MIME types that they send, I can see also application/x-qt-windows-mime;value="Shell IDList Array" type, which I am missing in my example. So this is what I assume is the problem, Edge probably expects this MS-centric data type. I would also like to wrap data in this format but I do not know how to do it.
I assume I will have to use Win32 API. So I browsed around and got some snippets which should be able to create some useful data structures...
QVector<LPITEMIDLIST> idLists;
for (const QString &nativePath: qAsConst(nativePaths))
{
PCWSTR pszFile = PCWSTR(nativePath.utf16());
LPITEMIDLIST idl = ILCreateFromPathW(pszFile);
if (idl == nullptr)
{
for (LPITEMIDLIST pid : qAsConst(idLists))
ILFree(pid);
return nullptr;
}
idLists.append(idl);
}
IShellItemArray *iArray = nullptr;
HRESULT result = SHCreateShellItemArrayFromIDLists(UINT(idLists.size()), (LPCITEMIDLIST*)idLists.data(), &iArray);
for (LPITEMIDLIST pid : qAsConst(idLists))
ILFree(pid);
This seems to me as the way that could lead to the desired outcome but there are still some steps missing. I do not know how to wrap this data (are they of any use at all?) into QMimeData::setData(). Any ideas?
I have a class that composes a palette and assigns it to the application using QApplication::instance()->setPalette(QPalette palette).
And it effectively works.
But then I try to use QPalette QApplication::instance()->palette() to extract some colours.
But here it does not work, it just returns the default palette, not the current one.
After I have discovered that it is working as supposed and described in the documentation.
And now I have just 2 questions:
Why it is working in such a strange, useless and counter-intuitive
mode?
How I can retrieve the palette which was set using
QApplication::instance()->setPalette(QPalette palette)?
P.S. No, I can't keep that palette elsewhere.
I think it is an issue of your Qt version (you marked the question as Qt 5 but didn't indicate a specific version), or you have something else in your project that is resetting the palette (you mentioned it has a large code base).
This minimum example shows correct behavior, at least with Qt 5.12.3 32bits, Windows, VS 2017:
#include <QApplication>
#include <QPalette>
#include <QDebug>
#include <QTimer>
#include <QWidget>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
const auto group = QPalette::Active;
const auto role = QPalette::Text;
auto palette = QApplication::palette();
qDebug() << "palette before:" << palette.color(group, role).name();
palette.setColor(group, role, "#123456");
qDebug() << "palette set:" << palette.color(group, role).name();
QApplication::setPalette(palette);
const auto palette2 = QApplication::palette();
qDebug() << "palette after:" << palette2.color(group, role).name();
QTimer::singleShot(100, [=]() { // check palette after the events loop has started
const auto palette3 = QApplication::palette();
qDebug() << "palette after 100ms:" << palette3.color(group, role).name();
});
QWidget w;
w.show();
return a.exec();
}
I've used QApplication::palette my self to retrieve custom palettes in different projects and had no issues at all.
QGuiApplication::setPalette is documented to change the default palette, so basically I think default palette means the palette used if a widget doesn't specify the other one; not the default system palette.
PS: I couldn't make it compile when using QApplication::instance()->setPalette since QApplication doesn't defines instance() but it falls to QCoreApplication::instance(), which obviously returns a QCoreApplication. Probably just a typo when you wrote the question, but I thought it deserved some lines. Given that the palette related methods are static, I decided to use those in the example, but I had the same results using the singleton from qApp.
I have a project which must support multiple ancient languages. My problem is that I have an ancient Old Turkic character (the language is written right-to-left) but I can't display the characters in a Qt Label like this:
//main.cpp
#include <QApplication>
#include <QString>
#include <QLabel>
int main(int argc, char** argv[])
{
QApplication app(argc, argv);
QString str = "\U00010C00"; // Character I wanted to display
QLabel *label = new QLabel(str);
label -> show();
return app.exec();
}
When I run this, in the label it prints a square which indicates that, I think, the character couldn't be found. How can I fix this problem?
A square is being displayed at the right of the window, so there is not a problem with the location of the character. My OS is Ubuntu 12.04 x64 and my Qt version is 5, by the way. I have the Old Turkic Unicode font.
You need to tell the label which font it should use.
QFont labelFont = QFont( "Old Turkic" );
label->setfont( labelFont );
My goal is to build a Game Boy emulator. In order to do this, I would like to embed an SDL2 surface into a wxWidgets window.
I found this tutorial: http://code.technoplaza.net/wx-sdl/part1/, but my program crashes as soon as I run it. However I suspect this was intended for SDL1.2. Part of the program is shown below.
It seems that if I call SDL_Init() and also attempt to show a wxFrame (which, in this case, is MainWindow), it shows the window for a second and then the program crashes. I commented all other calls to SDL in my program so far, so it seems the problem lies with calling Show() on a wxFrame and initing SDL2 in the same program.
So the question is: can SDL2 and wxWidgets 3 work together? If not, could you guys suggest to me good alternatives a GUI of a Game Boy emulator? Does wxWidgets have its own graphics frame like Qt does (I'd rather avoid Qt)?
Thanks very much!
#include "MainApp.h"
#include "MainWindow.h"
#include <stdexcept>
namespace GBEmu {
static void initSDL() {
//This and SDL_Quit() are the only calls to the SDL library in my code
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
throw std::runtime_error("Fatal Error: Could not init SDL");
}
}
bool MainApp::OnInit()
{
try {
//If I comment out this line, the MainWindow wxFrame shows up fine.
//If I leave both uncommented, the window shows up quickly and then
//crashes.
initSDL();
//If I comment out this line and leave initSDL() uncommented,
//the program will not crash, but just run forever.
(new MainWindow("GBEmu", {50,50}, {640,480}))->Show();
} catch(std::exception &e) {
wxLogMessage(_("Fatal Error: " + std::string(e.what())));
}
return true;
}
int MainApp::OnExit() {
SDL_Quit();
return wxApp::OnExit();
}
}
wxIMPLEMENT_APP(GBEmu::MainApp);
EDIT: Here is more information on how it crashes: It crashes with a Segfault in what seems to be the pthread_mutex_lock disassembly file. This is the output in the console with stack trace:
Starting /home/dan/Documents/devStuff/GBEmuWx-build/GBEmuWx...
The program has unexpectedly finished.
/home/dan/Documents/devStuff/GBEmuWx-build/GBEmuWx crashed
Stack trace:
Error: signal 11:
/home/dan/Documents/devStuff/GBEmuWx-build/GBEmuWx(_ZN5GBEmu7handlerEi+0x1c)[0x414805]
/lib/x86_64-linux-gnu/libc.so.6(+0x36ff0)[0x7fb88e136ff0]
/lib/x86_64-linux-gnu/libpthread.so.0(pthread_mutex_lock+0x30)[0x7fb88c12ffa0]
/usr/lib/x86_64-linux-gnu/libX11.so.6(XrmQGetResource+0x3c)[0x7fb88d1ca15c]
/usr/lib/x86_64-linux-gnu/libX11.so.6(XGetDefault+0xc2)[0x7fb88d1a7a92]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x94dcf)[0x7fb88af8edcf]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x97110)[0x7fb88af91110]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(cairo_surface_get_font_options+0x87)[0x7fb88af63e07]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x2b61f)[0x7fb88af2561f]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x2ef95)[0x7fb88af28f95]
This is a screenshot of where it seems to fail (line 7):
Update: In my MainWindow class, I attach a menu bar to the window. However, it seems when I comment out the setting of the menu bar, the window will show up fine even with initing of SDL. The menu bar will show up fine if I have initSDL() commented out but not the setting of the menu bar. Here is where I set the menu bar:
MainWindow::MainWindow(const wxString &title, const wxPoint &pos, const wxSize &size)
:wxFrame(nullptr, wxIDs::MainWindow, title, pos, size){
wxMenu *fileMenu = new wxMenu;
fileMenu->Append(wxID_EXIT);
wxMenuBar *menuBar = new wxMenuBar;
menuBar->Append(fileMenu, "&File");
//commenting this line out will allow the window to showup
//and not crash the program
SetMenuBar(menuBar);
}
You are experiencing an old heisenbug.
The workaround is simple: you have to initialize SDL before wxWidgets (basically, before GTK). To achieve this, you have to change
wxIMPLEMENT_APP(GBEmu::MainApp);
to
wxIMPLEMENT_APP_NO_MAIN(GBEmu::MainApp);
so that wxWidgets doesn't hijack your main().
Then you have to create main() manually. In it, initialize SDL, then call wxEntry():
int main(int argc, char** argv)
{
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
std::cerr << "Could not initialize SDL.\n";
return 1;
}
return wxEntry(argc, argv);
}
More about the bug:
I have googled around a bit and found that this bug has come up in a few places over the years. There are open reports in many bug trackers that have stack traces very similar to the one you get here (with debug symbols).
The oldest report I could find is from 2005 (!!) from the cairo bug tracker (https://bugs.freedesktop.org/show_bug.cgi?id=4373).
My best guess is that the real hiding place of this bug in either in GTK, cairo, or X. Unfortunately I do not currently have the time to look into it more in depth.
EDIT: I managed to get a compiling and non crashing version. The only thing left is to get the desired output, however this particular question (why it crashes) has been answered so I am closing the question. I will post the working code before the broken one.
Good day! I am trying to create a small example that will simply create a pdf document. Everything compiles, however when the program starts it simply crashes. I am using Qt version 5.0.0
---New working code---
int main( int argc, char **argv )
{
QApplication app( argc, argv );
QTextDocument doc;
doc.setHtml( "<p>A QTextDocument can be used to present formatted text "
"in a nice way.</p>"
"<p align=center>It can be <b>formatted</b> "
"<font size=+2>in</font> <i>different</i> ways.</p>"
"<p>The text can be really long and contain many "
"paragraphs. It is properly wrapped and such...</p>" );
QPrinter printer;
printer.setOutputFileName("C:\\Users\\SameTime\\Desktop\\Cutie\\PDFPrintMaybe");
printer.setOutputFormat(QPrinter::PdfFormat);
doc.print(&printer);
printer.newPage();
return 0;
}
Here is the project code:
#-------------------------------------------------
#
# Project created by QtCreator 2013-06-08T10:07:11
#
#-------------------------------------------------
QT += core
QT -= gui
QT += printsupport
TARGET = PDFPrintMaybe
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
----Old code with error---
And here is the main cpp:
#include <QCoreApplication>
#include <QTextDocument>
#include <QPrinter>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTextDocument doc;
doc.setHtml("<h1>Testing, testing, is this thing on?!</h1>");
QPrinter printer;
printer.setOutputFileName("C:\\Users\\SameTime\\Desktop\\Cutie\\PDFPrintMaybe");
printer.setOutputFormat(QPrinter::PdfFormat);
doc.print(&printer);
printer.newPage();
return a.exec();
}
I am a bit at a loss since it is compiling but crashing (almost) instantly when ran.
Try to create the objects on the heap otherwise they get automatically deleted when they ran out of scope, then the framework probably tries to delete them again and crashes.
QTextDocument *doc = new QTextDocument();
doc->setHtml("<h1>Testing, testing, is this thing on?!</h1>");
QPrinter* printer = new QPrinter();
printer->setOutputFileName("C:\\Users\\SameTime\\Desktop\\Cutie\\PDFPrintMaybe");
printer->setOutputFormat(QPrinter::PdfFormat);
doc->print(printer);
printer->newPage();