running draw_polygon example in CGAl package in qt widget application - c++

I try to following CGAL example in Qt widget application :
example
main.ccp:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.ccp :
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/draw_polyhedron.h>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
void MainWindow::on_pushButton_clicked()
{
QString fileName = QFileDialog::getOpenFileName(this,tr("Open .off model"), "/home", tr("*.off"));
draw_poly(fileName);
}
void MainWindow::draw_poly(QString fileName)
{
QByteArray inBytes;
const char *c;
inBytes = fileName.toUtf8();
c = inBytes.constData();
std::ifstream input(c);
if (!input || !(input >> mesh) || mesh.is_empty()) {
std::cerr << "Not a valid off file." << std::endl;
// return 1;
}
input >> mesh;
CGAL::draw(mesh);
}
when I ran it , it open dialog file to select .off file ,then it shows the following error:
QCoreApplication::exec: The event loop is already running
any help ,please ?

I'm using Qt5 in daily business, and once considered CGAL as possible application base (without going further into this direction – not yet). Hence, this question made me curious.
I digged through the source code of CGAL on github and found out why the error message
QCoreApplication::exec: The event loop is already running
occurs.
For this, I copied the relevant lines from CGAL on github: Polyhedron/include/CGAL/draw_polyhedron.h:
template<class Polyhedron, class ColorFunctor>
void draw(const Polyhedron& apoly,
const char* title,
bool nofill,
const ColorFunctor& fcolor)
{
#if defined(CGAL_TEST_SUITE)
bool cgal_test_suite=true;
#else
bool cgal_test_suite=false;
#endif
if (!cgal_test_suite)
{
int argc=1;
const char* argv[2]={"polyhedron_viewer","\0"};
QApplication app(argc,const_cast<char**>(argv));
SimplePolyhedronViewerQt<Polyhedron, ColorFunctor>
mainwindow(app.activeWindow(), apoly, title, nofill, fcolor);
mainwindow.show();
app.exec();
}
}
Looking at this source code, it becomes obvious that CGAL::draw() is a small ful-featured Qt application in itself which establishs its own QApplication instance. The OP in turn tried to embed the CGAL::draw() in her/his own Qt application. It is not allowed to instance any derivates of QCoreApplication more than once (according to Qt doc. of QApplication):
For any GUI application using Qt, there is precisely one QApplication object, no matter whether the application has 0, 1, 2 or more windows at any given time.
(Emphasizing not mine.)
The CGAL doc. provides an (even shorter) example in Polyhedron/draw_polyhedron.cpp to do this right:
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/draw_polyhedron.h>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
int main(int argc, char* argv[])
{
Polyhedron P;
std::ifstream in1((argc>1)?argv[1]:"data/cross.off");
in1 >> P;
CGAL::draw(P);
return EXIT_SUCCESS;
}
but there is no place to insert the QFileDialog at the right point.
Hence, CGAL::draw() is the wrong tool for what OP (probably) intends to do – embed CGAL polyhedron rendering into a Qt application. For this, it is necessary to use the things directly which are called somewhere inside of CGAL::draw().
So, this is what seems appropriate to me:
making SimplePolyhedronViewerQt<Polyhedron, ColorFunctor> a (main or child) widget in OPs Qt application.
I then walked a bit through the github repo to find out from which Qt widget CGAL::SimplePolyhedronViewerQt<Polyhedron, ColorFunctor> is actually derived from and found the following inheritance:
CGAL::SimplePolyhedronViewerQt<Polyhedron, ColorFunctor>
|
V
CGAL::Basic_viewer_qt
|
V
CGAL::QGLViewer
|
+--------------+--------------+
| |
V V
QOpenGLWidget QOpenGLFunctions
So, CGAL::SimplePolyhedronViewerQt<Polyhedron, ColorFunctor> can be used like any QWidget (which involves making it the main window). It can become as well the center widget of a QMainWindow which gets a menu bar/tool bar with the QAction to open the QFileDialog, request a file path, open a file stream with this file path, and load a mesh from this file stream.
There is another minor detail where I stumbled over: The CGAL::Polyhedron has to be given to the CGAL::SimplePolyhedronViewerQt in the constructor and by const reference. To consider this, it's IMHO necessary (after successful loading of mesh) to construct the CGAL::SimplePolyhedronViewerQt instance by new and set/add it to parent widget afterwards. If this is not acceptable it's probably necessary to go even deeper and replace the CGAL::SimplePolyhedronViewerQt by an own implementation, using the source code of the former as “cheat-sheet”.
This is how such an application could look like:
#include <fstream>
#include <QtWidgets>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/draw_polyhedron.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
CGAL::DefaultColorFunctorPolyhedron fColor;
Polyhedron mesh;
// setup UI
QMainWindow qWin;
QToolBar qToolbar;
QAction qCmdLoad(QString::fromUtf8("Load File..."));
qToolbar.addAction(&qCmdLoad);
qWin.addToolBar(&qToolbar);
qWin.show();
// install signal handlers
QObject::connect(&qCmdLoad, &QAction::triggered,
[&qWin, &mesh, &fColor]() {
const QString filePath = QFileDialog::getOpenFileName(
&qWin,
QString::fromUtf8("Open .off model"),
QString::fromUtf8("/home"),
QString::fromUtf8("*.off"));
if (filePath.isEmpty()) return;
std::ifstream fIn(filePath.toUtf8().data());
if (!(fIn >> mesh) || mesh.is_empty()) {
qDebug() << "Loading of" << filePath << "failed!";
return;
}
qWin.setCentralWidget(
new CGAL::SimplePolyhedronViewerQt<Polyhedron, CGAL::DefaultColorFunctorPolyhedron>(
&qWin, mesh, "Basic Polyhedron Viewer", false, fColor));
qWin.centralWidget()->show();
});
// runtime loop
return app.exec();
}
Please, take this with a “grain of salt” – I've no CGAL at hand and couldn't compile/test the above code.

CGAL::draw() already handles the Qt stuff. You are trying to open a mainwindow in another one. Just call CGAL::draw(mesh) in your main() function without anything else and it will work.
EDIT: Which is exactly what Sheff explained in a much more detailed way.

Related

Why is QAudioRecorder not recording through the constructor?

header
#ifndef AUDIORECORD_H
#define AUDIORECORD_H
#include <QMediaRecorder>
#include <QAudioRecorder>
#include <QUrl>
class AudioRecorder : public QAudioRecorder
{
Q_OBJECT
public:
AudioRecorder(QObject * parent);
~AudioRecorder(){}
};
#endif // AUDIORECORD_H
source
#include "audiorecord.h"
#include<iostream>
using namespace std;
AudioRecorder::AudioRecorder(QObject * parent = 0)
{
this->setOutputLocation(QUrl::fromLocalFile("test.mp3"));
int x = 0;
while ( x > 10000)
{
this->record();
x++;
}
this->stop();
std::cout<<"\ndsffsdf\n";
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "audiorecord.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QObject p;
AudioRecorder obj(&p);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
This does not produce any error but it does not record also. I am not expecting any quality or full fledged recording.
I just want to see how this recorder works.
That test.mp3 is not getting saved.
What bare minimum can I add or subtract to it to make it record something and save?
Cause
What would be if I tell you 10 000 times: Go buy some milk, while firmly holding your hand, then just before I let you go to say: Ah, forget it? Would you be able to buy the milk?
You are doing the same with your code:
int x = 0;
while ( x > 10000)
{
this->record();
x++;
}
this->stop();
You are calling 10 000 times QAudioRecorder::record, but you do not let Qt get to the event loop and actualy execute your command. Then just before Qt gets to the event loop, you say: stop.
Solution
First of all, you do not need to subclass QAudioRecorder, because you do not add any new functionality to it. Just create an instance of the class and use it.
Second, record and stop are slots. Connect them to the clicked signal of the corresponding push buttons in you GUI, e.g.:
auto *audioRecorder = new QAudioRecorder(this);
...
connect(btnRecord, &QPushButton::clicked, audioRecorder, &QAudioRecorder::record);
connect(btnStop, &QPushButton::clicked, audioRecorder, &QAudioRecorder::stop);
Note: For more information, please take a look at the example from the documentation.

QCompleter::activated disconnected after losing and gaining focus

I found a strange case which I do not understand. Maybe it is a Qt bug, maybe I am doing something wrong.
A header:
// File mylineedit.h
#pragma once
#include <QLineEdit>
#include <QDebug>
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit MyLineEdit(QWidget *parent = nullptr) : QLineEdit(parent) { }
public slots:
void onCompleterActivated(const QString& text) { qDebug() << "MyLineEdit" << text; }
};
And the main source file:
// File main.cpp
#include <QApplication>
#include <QWidget>
#include <QStringListModel>
#include <QCompleter>
#include <QVBoxLayout>
#include "mylineedit.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QLineEdit* lineEdit1 = new MyLineEdit();
QLineEdit* lineEdit2 = new MyLineEdit();
auto layout = new QVBoxLayout(&w);
layout->addWidget(lineEdit1);
layout->addWidget(lineEdit2);
lineEdit1->setCompleter(new QCompleter());
auto model = new QStringListModel(QStringList() << "A" << "B" << "C");
lineEdit1->completer()->setModel(model);
QObject::connect(lineEdit1->completer(), SIGNAL(activated(QString)), lineEdit1, SLOT(onCompleterActivated(QString)));
w.show();
return a.exec();
}
Once you run this, you can get a completer with values "A", "B", "C" in the first line edit. When you select any of these values, it will print the message to the console. This is correct. But then change focus to the other line edit and then back. Try picking "A", "B", "C" again. No message is printed out, the signal/slot seems disconnected. Any ideas?
Tested with MinGW 5.3.0 and MSVC 2015 using with Qt 5.9.2.
I modified your sample slightly and tried to reproduce the behavior you described but I couldn't:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version: " << QT_VERSION_STR;
// main application
QApplication app(argc, argv);
// setup GUI
QWidget qWin;
QVBoxLayout qVBox;
QLineEdit qEdit1;
qVBox.addWidget(&qEdit1);
QCompleter qCompl1;
QStringListModel qComplModel(QStringList() << "A" << "B" << "C");
qCompl1.setModel(&qComplModel);
qEdit1.setCompleter(&qCompl1);
QLineEdit qEdit2;
qVBox.addWidget(&qEdit2);
qWin.setLayout(&qVBox);
qWin.show();
// install signal handlers
QObject::connect(&qCompl1,
static_cast<void(QCompleter::*)(const QString&)>(
&QCompleter::activated),
[](const QString &text)
{
qDebug() << "Activated: " << text;
});
// run-time loop
return app.exec();
}
The significant differences in my sample:
I used Qt5 style signal handlers (as I'm used to).
I didn't new the Qt widgets (as I'm used to when I write minimal samples).
For me, it's hard to believe that one of these changes makes your described issue unbroken.
I compiled and tested with VS2013, Qt 5.9.2 on Windows 10 (64 bit):
I did the following interactions:
click in qEdit1
type A and click on item A in the popup menu
Output:
Activated: "A"
I continued with:
click in qEdit2
type B
click in qEdit1
erase text, type B, and click on item B in the popup menu
Output:
Activated: "B"
It works like expected.
After some conversation, I had a look at woboq.org in the source code of QLineEdit:
The interesting part is in QLineEdit::focusOutEvent:
if (d->control->completer()) {
QObject::disconnect(d->control->completer(), 0, this, 0);
}
If I read this right, all signal handlers of QLineEdit (emitted by the set completer) are disconnected. I believe this is the reason for the observed issue. (Therefore, it works for lambdas and methods of other classes.)

qt memory issues with camerainfo and combobox.currentText()

I am trying to grab the names of webcams plugged into my computer and shove them into a combobox, then access the name later. Here is my code:
#include <QApplication>
#include <QComboBox>
#include <QCameraInfo>
#include <iostream>
int main(int argc, char *argv[])
{
QApplication app{ argc, argv };
QComboBox combo;
QList<QCameraInfo> info = QCameraInfo::availableCameras();
foreach(QCameraInfo i, info)
combo.addItem(i.description());
combo.show();
std::cout << combo.currentText().toStdString() << std::endl;
return app.exec();
}
The code creates and shows a combo box that has the name of a webcam that I have plugged in to the computer. It will then toss me an access violation exception in trying to print the combo box string to the console.
If I comment the cout line out, all is well, but on exit I get a Debug Assertion Failed! message:
Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
which I take to mean I am deleting an object that has been deleted (the QString in the combobox???).
If I change the code to fill the combo box with dummies:
#include <QApplication>
#include <QComboBox>
#include <QCameraInfo>
#include <iostream>
int main(int argc, char *argv[])
{
QApplication app{ argc, argv };
for(int i=0; i<2; i++)
combo.addItem(QString("la la la");
combo.show();
std::cout << combo.currentText().toStdString() << std::endl;
return app.exec();
}
I get the same error on the cout, but if I comment that line out, the application exits correctly. I am using Visual Studio 2013, Windows 7, and Qt5.
Now it works. I kept the same source code, but completely scrapped the existing project and started a new one from scratch.
I've discovered that if I set the Runtime Library flag to Multi-Threaded DLL Debug, I will get access violation errors. If I set it to Multi-Threaded DLL, it is fine.
There may have been some other project settings that contributed, but this seems to be the main culprit.

c++ gui button output

i have a few questions regarding the gui of cplusplus using Qt creator
well i output an array using a forloop when user's choice is for example "1"
so in qt i created a button for that and i linked it with another window
so when i press on the button it opens another window
now i want to add the output of the forloop into this window
should i include iostream in the new window's .cpp file?
or what should i enter exactly?
in the mainwindow.cpp file here is the code i used to open a new window
void MainWindow::on_pushButton_clicked()
{
movies movies;
movies.setModal(true);
movies.exec();
}
thanks.
You should add a QTextEdit to your window (can be done via Qdesigner). And give this object a name e.g. Textout. Then in the code you should get a pointer to this object through your ui object. And you can use one of many methods to set the text of this object. setText is one option
ui->Textout->setText(Your_output_as_qstring)
Your can use QTextStream to format your text if necessary. Formating can be done with QString as well.
example:
#include <sstream>
#include <QLabel>
#include <QApplication>
int main(int argc, char *argv[])
{
std::stringstream ss;
for (auto s: {"first line", "second line"})
ss << s << std::endl;
QApplication a(argc, argv);
QLabel l;
l.setText(ss.str().c_str());
l.show();
return a.exec();
}

QTextObjectInterface with Qml TextEdit (QQuickTextEdit)

I registred handler for simple QTextObjectInterface, that draws just 10x10 red rectangle.
When i used QTextEdit in normal QWidget app, it worked.
When i used QQuickTextEdit (TextEdit qml component) in Qt Quick app, it doesn't worked (nothing is drawed, but the rectangle in TextEdit is reserved, because when i change cursor position, i notice that there is something, but just empty space, nothing is drawed.
The QTextObjectInterface intrinsicSize method is called (that explains why i see there is empty space 10x10), but the drawObject method isn't.
I did some research and i found that actually the problem is probably here:
QQuickTextEdit.cpp from Qt 5.3.0 sources (line 1821)
QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) {
.
.
.
if (textFrame->firstPosition() > textFrame->lastPosition()
&& textFrame->frameFormat().position() != QTextFrameFormat::InFlow) {
updateNodeTransform(node, d->document->documentLayout()->frameBoundingRect(textFrame).topLeft());
const int pos = textFrame->firstPosition() - 1;
ProtectedLayoutAccessor *a = static_cast<ProtectedLayoutAccessor *>(d->document->documentLayout());
QTextCharFormat format = a->formatAccessor(pos);
QTextBlock block = textFrame->firstCursorPosition().block();
node->m_engine->setCurrentLine(block.layout()->lineForTextPosition(pos - block.position()));
node->m_engine->addTextObject(QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document,
pos, textFrame->frameFormat().position());
nodeStart = pos;
}
it never reaches the point where node->m_engine->addTextObject is called.
It is because
this part of if condition textFrame->firstPosition() > textFrame->lastPosition() is evaluated to false.
I tried std::cout the firstPostion and the lastPosition when i established the context and firstPosition is 0, lastPosition is 1.
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QTextDocument>
#include <QQuickTextDocument>
#include <iostream>
#include <QTextCursor>
#include <QTextBlock>
#include <QPainter>
#include <QAbstractTextDocumentLayout>
#include <QTextCharFormat>
#include "qmlcomponentspace.h"
#include <QTextEdit>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QTextDocument * doc = engine.rootObjects().first()->findChild<QObject *>("editor")->property("textDocument").value<QQuickTextDocument *>()->textDocument();
QTextCursor cur(doc);
int objectType = QTextFormat::UserObject + 1000;
QmlComponentSpace * component = new QmlComponentSpace();
doc->documentLayout()->registerHandler(objectType, component);
QTextCharFormat fmt;
fmt.setObjectType(objectType);
fmt.setForeground(Qt::red);
fmt.setBackground(Qt::red);
cur.movePosition(QTextCursor::End);
cur.insertText(QString(QChar::ObjectReplacementCharacter), fmt);
std::cout << "FIRST:" << doc->rootFrame()->firstPosition() << std::endl;
std::cout << "END:" << doc->rootFrame()->lastPosition() << std::endl;
return app.exec();
}
What i am missing?
The documentation says at
http://doc.qt.io/qt-5/qquicktextdocument.html#details
Warning: The QTextDocument provided is used internally by Qt Quick elements to provide text manipulation primitives. You are not allowed to perform any modification of the internal state of the QTextDocument. If you do, the element in question may stop functioning or crash.