I need to create a very custom widget for printing. It has to be multi-platform as well. For consistency, the widget should be similar looking in windows as in linux or mac... After studying the Qt code, which uses the Windows print dialog, I gave up trying to subclass Qt print dialog, and made my own widget.
So, now I am on step 1: populate the list of printers on the system. I added the following code, to be called on each "show()" - just in case printers on the system change during program execution - and it works, but it is extremely slow:
I create a map of index/printer, and add the default printer as index -1, to tell the widget which one it is.
QMap<int, QString> PrintController::getListOfSystemPrinters()
{
QMap<int, QString> printerNames;
#ifdef Q_OS_WIN32
#ifdef NOT_QT_4 // I tried to use "availablePrinterNames" thinking it will be faster but it actually seems slower
QPrinter currentPrinter;
QString printerName = currentPrinter.printerName();
QStringList printerNameList = QPrinterInfo::availablePrinterNames();
int index = 0;
foreach(QString printerName1, printerNameList)
{
printerNames.insert(index, printerName1);
if(printerName == printerName1)
printerNames.insert(-1, printerName1);
++index;
}
#else
QPrinter currentPrinter;
QString printerName = currentPrinter.printerName();
QList<QPrinterInfo> printers = QPrinterInfo::availablePrinters();
int index = 0;
foreach(QPrinterInfo printerInfo, printers)
{
QString printerName1 = printerInfo.printerName();
printerNames.insert(index, printerName1);
if(printerName == printerName1)
printerNames.insert(-1, printerName1);
++index;
}
#endif
#elif defined Q_OS_UNIX
#endif
return printerNames;
}
This is the slowest piece of code I have ! I don't see another way to get all printer names... But I must be doing something wrong !
The Qt 5 version is slightly slower than the Qt 4 version... Either way, they are both slow....
The call to create a QPrinterInfo is slow.
So... are there alternatives ?
How can I get the list of printer names in Windows ?
Note this must work in Qt 4.7-5.x
Get printer list asynchronously:
class Class : public QObject {
Q_OBJECT
Q_SIGNAL void hasPrinters(const QList<QPrinterInfo> &);
Q_SIGNAL void hasPrinterNames(const QStringList &);
/// This method is thread-safe
void getPrinters() {
#if QT_VERSION >= QT_VERSION_CHECK(5,3,0)
emit hasPrinterNames(QPrinterInfo::availablePrinterNames());
#else
emit hasPrinters(QPrinterInfo::availablePrinters());
#endif
}
void test() {
QtConcurrent::run(this, &Class::getPrinters);
}
};
The above compiles on Qt 4.7 & up, using either C++98 or C++11.
Connect to the hasPrinterNames/hasPrinters signal to be notified when the printer list is available, then populate your dialog.
You might be lucky and availablePrinterNames/availablePrinters will be thread-safe. I haven't checked if it is.
On Qt 5.3 and newer, only create the QPrinterInfo for a given printer once your user has selected it, and you might want to create it concurrently as well.
Related
I prepared this small verifiable .ui in Figure 1 that replicates the issue I have:
I am trying to use the QPushButton "Print Screen Both Images" to incrementally save images on Left and Right of the QGraphicsView into two different folders present on my Desktop, see below Figure 2:
I can take a print screen of either the leftScene or the rightScene by just clicking on their related QPushButton Print Screen Left and Print Screen Right.
However, I am trying for this specific case not to use QFileDialog as I need to silently and incrementally save the images in the two different destination folders as I move on with the right/left arrow.
See below the snipped of code I am using:
mainwindow.h
public:
void bothPrintScreen(const std::string& pathImg);
private slots:
void on_bothPrintScreen_clicked(const std::string& imgPath);
private:
int counterA=0;
int counterB=0;
mainwindow.cpp
void MainWindow::on_bothPrintScreen_clicked(const std::string& imgPath)
{
bothPrintScreen(imgPath);
}
void MainWindow::bothPrintScreen(const std::string& pathImg){
cv::Mat left, right;
std::string outA = pathImg+"/printScreenA_"+std::to_string(counterA++)+".png";
cv::imwrite(outA,left);
std::string outB = pathImg+"/printScreenB_"+std::to_string(counterB++)+".png";
cv::imwrite(outB,right);
}
I am missing something in the code but I am not sure what exactly.
The compiler is seinding this allocate()/deallocate() error that I don't understand:
Please shed light on this matter.
It need to add OpenCV libraries to the your Qt project (like this)
INCLUDEPATH += -I/usr/local/include/opencv
LIBS += -L/usr/local/lib -lopencv_stitching -lopencv_superres ...and another libraries
I have a TS3 plugin in creation right here, which uses
System::Speech::Recognition for its SpeechRecognitinEngine. Now, I create an EventHandler for the SpeechRecognized event.
Well, my logging (and the actions of the plugin - None) tell me, that the Event is actually never triggered, even if you start and stop talking with the (somewhat) valid (parts of the) grammar.
I have no idea why this is. It happens in a DLL written in C++ CLI.
Now, my theory was that DLLs do not support event handerls... Might that be possible?
void recogn_speech() {
uint64 schid = ts3Functions.getCurrentServerConnectionHandlerID();
SpeechRecognitionEngine^ recognizer = gcnew SpeechRecognitionEngine();
System::Speech::Recognition::Grammar^ g = assembleGrammar();
recognizer->LoadGrammar(g);
recognizer->SetInputToDefaultAudioDevice();
char pluginPath[PATH_BUFSIZE];
ts3Functions.getPluginPath(pluginPath, PATH_BUFSIZE, pluginID);
String^ a = gcnew String(pluginPath);
a = a + "vctest_cpp_ts3\\signal_vc_start.wav";
char* newPath = (char*)(void*)Marshal::StringToHGlobalAnsi(a);
ts3Functions.playWaveFile(schid, newPath);
Marshal::FreeHGlobal((IntPtr)newPath);
recognizer->SpeechRecognized +=
gcnew EventHandler<SpeechRecognizedEventArgs^>(this, &tsapi::sre_SpeechRecognized);
}
void sre_SpeechRecognized(Object^ sender, SpeechRecognizedEventArgs^ e)
{
uint64 schid = ts3Functions.getCurrentServerConnectionHandlerID();
String^ recognRes = e->Result->Text->ToString();
interpretCommand(recognRes);
}
Full Sourcecode on
GitHub
Your event handler looks correct. There's no issue with having events & event handlers across DLLs: It's all managed code, the DLL boundary doesn't matter here.
However, there is one possible issue:
void recogn_speech() {
...
SpeechRecognitionEngine^ recognizer = gcnew SpeechRecognitionEngine();
...
}
You might want to save your SpeechRecognitionEngine object somewhere so it doesn't get garbage collected.
Also, you may want to switch to the more C++-style of having class definitions in .h files, and implementations in .cpp files. As your code gets more complex and the classes need to refer to each other, having everything in one file will start to become an issue.
According to the documentation for
SDL_bool SDL_GetWindowWMInfo(SDL_Window* window,
SDL_SysWMinfo* info)
SDL_SysWMinfo* info's SDL_Version version member must be defined by the SDL_VERSION macro at compile time before it is passed.
Why does SDL_GetWindowWMInfo require the SDL version the calling code was compiled against? What would happen if SDL_GetWindowWMInfo did not check the SDL version?
It's pretty much like keltar said. This is from SDL_windowswindow.c:
SDL_bool
WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
{
const SDL_WindowData *data = (const SDL_WindowData *) window->driverdata;
if (info->version.major <= SDL_MAJOR_VERSION) {
info->subsystem = SDL_SYSWM_WINDOWS;
info->info.win.window = data->hwnd;
info->info.win.hdc = data->hdc;
return SDL_TRUE;
} else {
SDL_SetError("Application not compiled with SDL %d.%d\n",
SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
return SDL_FALSE;
}
}
This function fills in a user-provided struct. The danger is that this struct is liable to change as the platform support in SDL changes (as opposed to actual feature/API changes that are more apparent in a new version number).
If that struct definition has changed between versions of SDL (say, you use updated headers but old dll), this requirement allows SDL to detect the problem before it stomps your program's memory.
I am struggling with getting multi-touch to work on a couple of QWidgets that I have added to a QGraphicsView. I have created a subclass of QWidget in which I set up a QGraphicsScene and QGraphicsView. This is my (test) subclass of QWidget:
#include "qttest1.h"
#include <QtWidgets>
#include <QTouchEvent>
qttest1::qttest1(QWidget *parent)
: QWidget(parent)
{
setEnabled(true);
if(!QCoreApplication::testAttribute(Qt::AA_DontCreateNativeWidgetSiblings))
setAttribute(Qt::WA_NativeWindow);
setAttribute(Qt::WA_AcceptTouchEvents);
scene = new QGraphicsScene(this);
scene->setSceneRect(0, 0, 1920, 1080);
graphicsView = new QGraphicsView(scene, this);
graphicsView->setRenderHints(QPainter::Antialiasing);
graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
graphicsView->setAttribute(Qt::WA_AcceptTouchEvents);
graphicsView->viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
QBoxLayout *layout = new QVBoxLayout;
layout->addWidget(graphicsView);
setLayout(layout);
}
qttest1::~qttest1() {}
void qttest1::showGraphics()
{
for(int i = 0; i < 10; i++)
{
Dial *dial = new QDial();
dial->move(i * 120 + 50, 200);
dial->resize(120, 120);
dial->setAttribute(Qt::WA_AcceptTouchEvents);
QGraphicsProxyWidget *proxy = scene->addWidget(dial);
proxy->setAcceptTouchEvents(true);
}
}
This is my main:
int main(int argc, char **argv)
{
QApplication app(argc, argv);
app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
QRect rect = app.desktop()->screenGeometry();
qttest1 test;
test.resize(rect.width(), rect.height());
test.showFullScreen();
test.showGraphics();
return app.exec();
}
I know the code isn't pretty and probably leaking a bit, but the point is to try to get multi-touch to work.
I can see and use every kind of widget I add to the scene, but as soon as I touch a dial it swallows every touch that comes after the first. Which makes the dial jump between several positions. What I want is that every dial (or any type of widget) can be used individually and at the same time. I am using QT 5.0.2, Windows 8 with a monitor that supports up to 10 touches.
The Qt docs state : -
Reimplement QWidget::event() or QAbstractScrollArea::viewportEvent()
for widgets and QGraphicsItem::sceneEvent() for items in a graphics
view to receive touch events.
With that, I believe that you need to handle the QEvent::TouchBegin, QEvent::TouchUpdate and QEvent::TouchEnd events, which I don't see in the code you've posted.
Qt may handle the first touch for you, but it's not going to know what you want to do with the second, third, fourth etc. simultaneous touches. For example, you may want your app to do any of the following with the second touch moving: -
1) Rotate the object that the first item is over
2) Scale the object that the first item is over
3) Select the second item
4) Translate the view
5) etc.
So, you need to handle the consecutive touches to do what you want it to do. Also, you may want to look at Gestures in Qt.
I wonder if it is possible to resize Windows OnScreen-keyboard in my program? What Windows methods to use for that?
simply use standard Win32 api.
I know this question is old, but the given answer is really short. To add value to this topic I could not resist to add the following information:
You could do something like this, the flag SWP_NOREPOSITION should make the iPosX and iPosY to be ignored by SetWindowPos. So only the width and height should change. I have not tested this code though.
HWND hWndOSK = FindWindow("IPTip_Main_Window", null); //Only the class is known, the window has no name
int iPosX=0;
int iPosY=0;
int iWidth=1000;
int iHeight=600;
if(hWndOSK != NULL)
{
//Window is up
if(!SetWindowPos(hWndOSK, HWND_TOPMOST, iPosX, iPosY, iWidth, iHeight, SWP_NOREPOSITION))
{
//Something went wrong do some error handling
}
}
SetWindowPos: http://msdn.microsoft.com/en-us/library/ms633545.aspx
FindWindow: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633499(v=vs.85).aspx