program crashes when trying to access clipboard - qt

I am trying to get clipboard data via QClipboard. Here is my code:
void MainWindow::getText()
{
QClipboard *clipboard = QGuiApplication::clipboard();
const QMimeData *mime = clipboard->mimeData (QClipboard::Selection);
QString originalText = clipboard->text(); // no crashes in windows
//QString originalText = mime->text (); //this line causing program crash
.................
}
getText() called every 5 second using QTimer. The above code works perfectly in linux, when I try to run the code in windows 7 it crashed.

clipboard->mimeData can be null, so you might want to either cache the previous state, or do the following:
QString originalText = mime ? mime->text() : QString();

Windows doesn't support QClipboard::Selection, that's why application crashes everytime. Here is how I solved it
QString originalText;
if(QSysInfo::productType() == "windows") {
QString clipboard = QApplication::clipboard()->text();
originalText = clipboard;
} else {
// for linux
QClipboard *clipboard = QGuiApplication::clipboard();
const QMimeData *mime = clipboard->mimeData (QClipboard::Selection);
originalText = mime->text ();
}

Related

How to link signal and slot when i change the font in the dialog

This is how i am currently choosing the font in my application.
void FontChange()
{
QString filePath = QFileDialog::getOpenFileName(NULL, tr("Open File"),
QStandardPaths::standardLocations(QStandardPaths::FontsLocation)[0],
tr("Fonts (*.ttf);;Everything (*.*)"), nullptr,
QFileDialog::DontUseNativeDialog);
if (filePath.isEmpty())
return;
QlineEditSetFont->setText(filePath);
stdstrLocation = filePath.toStdString();
this->isChanged = true; // this executes the function
}
I want to execute a function whenever i change my selection in the Dialog , currently i have to choose a font and than click on open to execute the function
////////////////////////////////////////////////////////////////////////////
Now i am using a non modal way but how can i determine if cancel has been pressed.
Further Edit
QFileDialog* dialog = new QFileDialog();
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setNameFilter("TTF (*.ttf)");
dialog->setOption(QFileDialog::DontUseNativeDialog);
dialog->setDirectory("C:\\Windows\\Fonts");
QObject::connect(dialog, &QFileDialog::currentChanged, [=](const QString &path) {
qDebug() << path; stdstrLocation = path.toStdString(); this->isChanged = true;
QStringList fileNames = dialog->selectedFiles();
qDebug() << "Selected FIles" << fileNames.size();
});
dialog->show();
You can't use the static convenience method but need to create the QFileDialog instance manually:
auto dialog = new QFileDialog(someParent);
dialog->setWindowTitle(tr("Open File"));
dialog->setDirectory(QStandardPaths::standardLocations(QStandardPaths::FontsLocation)[0]);
dialog->setNameFilter(tr("Fonts (*.ttf);;Everything (*.*)"));
// more setup...
connect(dialog, &QFileDialog::filesSelected, this, [this](const QStringList &selected) {
// handle selection change here
});
if (dialog->exec() == QDialog::Accepted) { // alternatively use open() to avoid blocking exec()
// do something with dialog->selectedFiles()...
}
delete dialog;
Actually, those are two different questions. The one from the title has been already answered. The answer to the second one, namely How can i determine if cancel has been pressed, lies in the documentation of QFileDialog::getOpenFileName itself:
If the user presses Cancel, it returns a null string.
With this in mind, you can do something like:
void FontChange()
{
QString filePath = QFileDialog::getOpenFileName(NULL, tr("Open File"),
QStandardPaths::standardLocations(QStandardPaths::FontsLocation)[0],
tr("Fonts (*.ttf);;Everything (*.*)"), nullptr,
QFileDialog::DontUseNativeDialog);
if (filePath.isNull()) {
// user pressed Cancel
} else if (filePath.isEmpty()) {
return;
} else {
QlineEditSetFont->setText(filePath);
stdstrLocation = filePath.toStdString();
this->isChanged = true; // this executes the function
}
}
You can of course rewrite the if part to be more suitable to your app's logic.
As a side note, QString::isEmpty also implies that it is NULL.

DDE connection failing for unknown reasons

I'm trying to create and implement a DDE dll with Qt but as for now I'm being unable to properly connect to a service which I know to be working after testing it with Excel.
The dll connection function is as following:
UINT respTemp;
respTemp = DdeInitializeA(&pidInst, NULL, APPCLASS_STANDARD | APPCMD_CLIENTONLY, 0L);
//handle error messages here
//...
//![]
hszService = DdeCreateStringHandleA(pidInst, (LPCSTR)service.utf16(), CP_WINANSI); //service.toLatin1().toStdString().c_str()
hszTopic = DdeCreateStringHandleA(pidInst, (LPCSTR)topic.utf16(), CP_WINANSI); //topic.toLatin1().toStdString().c_str()
hConv = DdeConnect(pidInst, hszService, hszTopic, NULL);
DdeFreeStringHandle(pidInst, hszService);
DdeFreeStringHandle(pidInst, hszTopic);
if (!hConv)
{
UINT ddeLastError = DdeGetLastError(pidInst);
switch (ddeLastError)
{
case DMLERR_DLL_NOT_INITIALIZED: return DDEConn_DLLNotInitialized;
case DMLERR_INVALIDPARAMETER: return DDEConn_InvalidParameter;
case DMLERR_NO_CONV_ESTABLISHED: return DDEConn_NoConvEstablished;
default: return DDEConn_NoConnectionStablished;
}
}
connStatus = true;
return DDEConn_NoError;
The test function is as follows:
void MainWindow::on_start_clicked()
{
const QString application = "profitchart"; //=profitchart|COT!VALE5.ult
const QString topic = "COT";
const QString item = "VALE5.ult";
test = CommDDE::instance();
CommDDE::DDEConnectionErrorList resp = test->connect(application,topic);
if (resp == CommDDE::DDEConn_NoError)
{
qDebug() << "request RESULT: " << test->request(item);
}
else
qDebug() << "Can't connect to application" << resp;
}
Always when I try to connect I get error DMLERR_NO_CONV_ESTABLISHED after the call to DdeConnect. I couldn't find guidence on what to do when such error occurs. I don't know too much about the details of configuring such functions so I used the default configuration used by a working dll from which I got part of the raw material for this dll. Should I try a different configuration I'm not aware of? Remembering that the call is working on Excel.
It would seem I found the answer: the commented way of writting the service and topic names were the right ways of passing the parameters to DdeCreateStringHandleA and DdeCreateStringHandleA.

How to implement clipboard actions for custom mime-types?

I am trying to implement copy/cut/paste in a complex application.
I have a QGraphicsScene that can contain QGraphicsItem subtypes of varied subtypes, fairly complex (with Item as a second parent storing custom properties).
I would copy/cut selected items, and paste them back in place.
I already have implemented it using a local version: a list of items.
void copyItemsActionOld()
{
foreach(QGraphicsItem* qItem, selectedItems())
{
Item* newItem = (dynamic_cast<Item*>(qItem))->createItemCopy();
m_itemClipboard.append(newItem);
}
}
On paste, I make a copy of all items in clipboard and add them to the scene. So simple.....
BUT
I need to implement it using the global system clipboard.
I saw that creating a custom mime type is as simple as calling setData on a QMimeData object, after I make up a format name... (I hope that is true)
static const QString _mimeType("application/myItem");
void copyItemsAction()
{
QMimeData* _mimeData = new QMimeData;
2 QByteArray _itemData = ?????;
_mimeData->setData(_mimeType, _itemData);
QClipboard* _clipboard = QApplication::clipboard();
_clipboard->clear();
_clipboard->setMimeData(_mimeData);
}
void pasteItemsAction()
{
QClipboard* _clipboard = QApplication::clipboard();
const QMimeData* _mimeData = _clipboard->mimeData();
QStringList _formats = _mimeData->formats();
foreach (QString _format, _formats)
{
if (_format == _mimeType)
{
QByteArray _itemData = _mimeData->data(_mimeType);
3 // then do what ? How do I parse it ?
}
}
}
My questions
1) Are the above fragments for copyItemsAction and pasteItemsAction anywhere close to how clipboard actions should work ?
2) How can I put item data in the QByteArray ?
3) How do I parse the data in QByteArray ?
4) Do I need to register the custom mime-type anywhere else ? (other than what I just did in my two functions); and will it be multi-platform ?
I have already implemented save and load functionality for all items. Something like...
void Item::saveItem(QDataStream &outFile)
{
outFile << type;
outFile << width;
outFile << color.name();
}
Can I use this to place the items data in the QByteArray ? (How ?)
I was on the right track, and I kept adding code to my question until I found how to make it work:
static const QString _mimeType("application/myItem");
void copyItemsAction()
{
QByteArray _itemData;
QDataStream outData(&_itemData, QIODevice::WriteOnly);
outData << selectedItems().size();
foreach(QGraphicsItem* qItem, selectedItems())
{
Item* item = dynamic_cast<Item*>(qItem);
item->saveItem(outData);
}
QMimeData* _mimeData = new QMimeData;
_mimeData->setData(_mimeType, _itemData);
_mimeData->setText("My Items");
QClipboard* _clipboard = QApplication::clipboard();
_clipboard->clear();
_clipboard->setMimeData(_mimeData);
}
void pasteItemsAction()
{
QClipboard* _clipboard = QApplication::clipboard();
const QMimeData* _mimeData = _clipboard->mimeData();
QStringList _formats = _mimeData->formats();
foreach (QString _format, _formats)
{
if (_format == _mimeType)
{
QByteArray _itemData = _mimeData->data(_mimeType);
QDataStream inData(&_itemData, QIODevice::ReadOnly);
int itemsSize;
inData >> itemsSize;
for (int i = 0; i < itemsSize; ++i)
{
Item* item = ...
item->loadItem(inData);
}
}
}
}
So, for question 1, yes I was on the right track;
For questions 2 and 3 - I was able to use a QDataStream to serialize info to/from the QByteArray.
If there is a better / more effective / faster way, I would love to know...
For question 4 - it seems that I can use just about any string, if all I want is to copy/paste within a single instance of my application.
It is also true if I want to use it between multiple applications, multiple instances of my application, or for drag-and-drop - on most platforms. (It does not seem to work between multiple applications/instances in the embedded platform I target.)
Caveat - it fails frequently when another clipboard using application is open, in windows.

use phonon crash in phonon_ds9d4.dll

use code :
Phonon::VideoPlayer *player = new Phonon::VideoPlayer(Phonon::MusicCategory, NULL);
QObject::connect(player, SIGNAL(finished()), player, SLOT(deleteLater()));
player->play(Phonon::MediaSource("c:/yaodong.mkv"));
but crash.
env is win7 and vs2008, qt 4.7.1
windows sdk is 7.1
dx sdk is Microsoft DirectX SDK (March 2009)
and i find the stack is
mediaobject.cpp (line 233) graph is null
} else if (!m_currentWork.url.isEmpty()) {
//let's render a url (blocking call)
hr = m_currentWork.graph->RenderFile(reinterpret_cast<const wchar_t *>(m_currentWork.url.utf16()), 0);
}
then i find run step to the function:
quint16 WorkerThread::addUrlToRender(const QString &url)
{
QMutexLocker locker(&m_mutex);
Work w;
w.task = Render;
//we create a new graph
w.graph = Graph(CLSID_FilterGraph, IID_IGraphBuilder);
w.url = url;
w.url.detach();
w.id = m_currentWorkId++;
m_queue.enqueue(w);
m_waitCondition.set();
return w.id;
}
the line : w.graph = Graph(CLSID_FilterGraph, IID_IGraphBuilder);
w.graph is null.
but i wrote the code outside :
IGraphBuilder *pGraph = NULL;
::CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER, IID_IGraphBuilder,
reinterpret_cast<void**>(&pGraph));
the pGraph is not null.
help. thanks!

How to use QFileDialog::getsaveFileName to save a ui file with QFormBuilder?

What I want:
When I call save(), I would like to use the QFileDialog to get the file, and save ui file with QFormBuilder(because it lets me save ui files recognizable by Qdesigner)
What I have:
I have a method called save()
void MainWindow::save()
{
QString savef = QFileDialog::getSaveFileName(this, tr("Save"), "file", tr("UI files (*.ui)"));
//here down I would like to use the savef to save ui file
QFormbuilder builder;
builder.save(savef, myui);
}
But savef is not QIODevice, and the Qt is complaining about it.
Any idea how I can do it?
Thanks.
You need to create a QFile and pass that to save():
QFile out(savef);
if (!out.open(QIODevice::WriteOnly)) {
const QString error = tr("Could not open %1 for writing: %2").arg(savef, out.errorString());
//report the error in some way...
return;
}
builder.save(&out, myui);
const bool flushed = out.flush();
if (!flushed || out.error() != QFile::NoError) { // QFormBuilder lacks proper error reporting...
const QString error = tr("Could not write form to %1: %2").arg(savef, out.errorString());
//report error
}
When using Qt 5.1 or newer, I'd use QSaveFile instead:
QSaveFile out(savef);
if (!out.open(QIODevice::WriteOnly)) {
const QString error = tr("Could not open %1 for writing: %2").arg(savef, out.errorString());
//report the error in some way...
return;
}
builder.save(&out, myui);
if (!out.commit()) {
//report error
}

Resources