I'm working on a feature in my Qt program where you have the option to store the locations of your application's windows in a profile manner and load that profile later. After some research I found QSettings quite handy and useful for storing UI info like x, y etc. For detecting the windows I decided to use XLib.
I'm very beginner to using Xlib, I found this code which recursively query any open window starting from ":0.0". Inside the foreach loop I did this save function:
int x, y;
int xGeo, yGeo;
int width, height, border, depth;
Display *disp = XOpenDisplay(":0.0");
Window rootWin = XDefaultRootWindow(disp);
QList<Window> windows = listXWindowsRecursive(disp, rootWin);
char* name = NULL;
XWindowAttributes* attributes;
foreach(Window win, windows)
{
attributes = new XWindowAttributes;
// Enumerate through all windows
if(XFetchName(disp, win, &name) && name != NULL)
{
if(strcmp(name, "Secondary Window") == 0)
{
Window child;
qDebug() << (name);
XTranslateCoordinates(disp, win, rootWin, 0, 0, &x, &y, &child);
qDebug() << "XC = " << x << " - " << "YC = " << y;
if(XGetGeometry(disp, win, &rootWin, &xGeo, &yGeo, &width, &height, &border, &depth))
qDebug() << "XGeo= " << x - xGeo << " - " << "YGeo= " << y - yGeo;
settings.setValue("secondaryWindow/x", x - xGeo);
settings.setValue("secondaryWindow/y", y - yGeo);
settings.setValue("secondaryWindow/width", width);
settings.setValue("secondaryWindow/height", height);
if(XGetWindowAttributes(disp, win, attributes))
{
qDebug() << "X = " << x - attributes->x << " - " << "Y = " << y - attributes->y;
}
}
}
}
This portion gets the Qt UI info like X and Y and stores them using QSettings
First thing I'm not sure if what I wrote is the right way to get the X and Y for the window because of these facts. Also I'm not sure if I'm correctly passing the required parameters.
Second thing, this is the load function:
if(settings.contains("secondaryWindow/x") && settings.contains("secondaryWindow/y"))
{
SecondaryWindow* win = new SecondaryWindow;
win->setGeometry(settings.value("secondaryWindow/x").toInt(),
settings.value("secondaryWindow/y").toInt(),
settings.value("secondaryWindow/width").toInt(),
settings.value("secondaryWindow/height").toInt());
win->show();
}
Here is the weird scenario, there is a button that opens the secondary window (using new and show) which works fine. Back to the main window clicking the save function, I get the correct secondary window info.
Now If I closed the secondary window and then clicked the load function, the secondary window opens correctly in the previous position BUT, clicking the save function again here will tell me that there are two "Secondary Window" instances but the second one has X and Y = 0.
By "closing the window" I mean using either the "X" button and using the close() slot. Could it be that the window is not closed correctly? I already implemented the closeEvent handler:
event->accept();
QWidget::closeEvent(event);
Any help is appreciated, Thanks!
Related
I am new to C++ gui design and I am not too familiar with using pointers. Recently I have run into a few problems when trying to get an OpenCV Mat Image to display in a PictureBox in a constructed gui. I have searching online and even found a very similar post to my question but when trying to implement the guidance I ran into an exception when trying to operate the gui.
A very similar post
Displaying webcam feed in cv::Mat format in a picturebox
Code I grabbed from this post to save you a click:
void DrawCVImage(System::Windows::Forms::Control^ control, cv::Mat& colorImage)
{
System::Drawing::Graphics^ graphics = control->CreateGraphics();
System::IntPtr ptr(colorImage.ptr());
System::Drawing::Bitmap^ b = gcnew System::Drawing::Bitmap(colorImage.cols,colorImage.rows,colorImage.step,System::Drawing::Imaging::PixelFormat::Format24bppRgb,ptr);
System::Drawing::RectangleF rect(0,0,control->Width,control->Height);
graphics->DrawImage(b,rect);
delete graphics;
}
Now I am trying to display a "video" feed (really an array of cv::Mat Objects) but I am having a
"Source Not Available"/System.ArgumentException: 'Parameter is not valid.'
screen come up when I attempt to call the function that houses that playback. I also know specific line of code that throws the issue is the line
System::Drawing::Bitmap^ b = gcnew System::Drawing::Bitmap(colorImage.cols,colorImage.rows,colorImage.step,System::Drawing::Imaging::PixelFormat::Format24bppRgb,ptr);
Now for specifics, the form has an event (currently the click on the picture box, but I want to move to a "play" button in the future) and on this event, the code:
private: System::Void leftEyeImage_Click(System::Object^ sender, System::EventArgs^ e) {
std::cout << "Click Received" << std::endl;
cv::Mat& frame = cv::imread("Desktop/testcapture.png");
std::cout << "Import successful" << std::endl;
drawLeftEye(this, frame);
}
This code does get execute on click and starts the function drawLeftEye. The function is a modified version of the code from the other post and is below:
This is on the ShowResults.cpp file
namespace DevProject {
void ShowResults::drawLeftEye(System::Windows::Forms::Control^ control, cv::Mat& framebmp) {
System::Drawing::Graphics^ graphics = control->CreateGraphics();
std::cout << "Now Here" << std::endl;
System::IntPtr ptr(framebmp.data);
// Issue line
System::Drawing::Bitmap^ b = gcnew System::Drawing::Bitmap(framebmp.cols, framebmp.rows, framebmp.step, System::Drawing::Imaging::PixelFormat::Format32bppRgb, ptr);
std::cout << "Converted successfully" << std::endl;
System::Drawing::RectangleF rect(0, 0, control->Width, control->Height); //No issue
graphics->DrawImage(b, rect);
std::cout << "Now Here before delete" << std::endl;
delete graphics;
//delete b;
}
}
I know based on my cout statements that I do make it into my function and I know my code compiles and runs through the function if I comment out the line:
System::Drawing::Bitmap^ b = gcnew System::Drawing::Bitmap(framebmp.cols, framebmp.rows, framebmp.step, System::Drawing::Imaging::PixelFormat::Format32bppRgb, ptr);
//As well as (but only because b is defined in the line above^
graphics->DrawImage(b, rect);
I am not quite sure how to fix this, my friend mentioned this could be a memory issue but I don't know how I would go about fixing it. It is also very possible I have made a simple mistake in the design of this or where my pointers are going and I am just not competent enough to know the error.
By the way the pointer for "this" that is called in the function is linked to the Windows Autogenerated code (from gui construction) of:
this->leftEyeImage->Anchor = System::Windows::Forms::AnchorStyles::None;
this->leftEyeImage->BorderStyle = System::Windows::Forms::BorderStyle::FixedSingle;
this->leftEyeImage->Location = System::Drawing::Point(11, 836);
this->leftEyeImage->Name = L"leftEyeImage";
this->leftEyeImage->Size = System::Drawing::Size(991, 646);
this->leftEyeImage->TabIndex = 4;
this->leftEyeImage->TabStop = false;
this->leftEyeImage->Click += gcnew System::EventHandler(this, &ShowResults::leftEyeImage_Click);
Any and all advice or tests would be very appreciated as I am both interested in the answer and the reasoning. Thanks in advance!
I am converting some code from using QWidget to QOpenGLWidget, I want to use double buffering to render the widget, so far:
void clsElevStrip::initializeGL() {
qDebug() << "clsElevStrip::initializeGL()";
initializeOpenGLFunctions();
//Get the openGL context
mpobjContext = context();
if ( mpobjContext != NULL ) {
//Setup surface
mobjFormat.setDepthBufferSize(24);
mobjFormat.setSamples(4);
mobjFormat.setVersion(3, 0);
mobjFormat.setProfile(QSurfaceFormat::NoProfile);
mobjFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
int intSB = (int)mobjFormat.swapBehavior();
qDebug() << "swapBehavour as set-up in format: " << QString::number(intSB);
mpobjContext->setFormat(mobjFormat);
intSB = (int)mpobjContext->format().swapBehavior();
qDebug() << "swapBehavour as set-up in context: " << QString::number(intSB);
}
}
I can see in the debugger that intSB is 2 when checking swap behaviour from the format, but when I check intSB as set in the context it is 0, not 2?
As a result of this anything I render to the context is visible.
Resolved:
I modified the code, adding
mpobjContext->create();
After:
mpobjContext->setFormat(mobjFormat);
Now it works!
I'm new to shell programming and having trouble getting the filepath (or really, any information) about which item is being clicked on in a window (desktop or otherwise). I'm following the general path laid out by the answer to Can i use Global System Hooks to capture which file was clicked on? but I'm not having any luck.
The clicking is the smaller issue here, so I've just substituted random values (where I know the desktop is and where a file should be located) for the mouse position. (Regardless, it doesn't work even when I'm trying this out on my mouse's current position).
LVHITTESTINFO hitTest = { 0 };
hitTest.pt.x = 55;
hitTest.pt.y = 230;
hitTest.flags = LVHT_ONITEM;
currWindow = WindowFromPoint(pt);
int index = ListView_HitTest(currWindow, &hitTest);
//cout << index + " index";
//cout << hitTest.iItem + " iltem ";
if (index != -1) {
//char* itemText = new char[256];
std::vector<wchar_t> itemText(1024);
ListView_GetItemText(window, index, 0, &itemText[0], 256);
PIDLIST_ABSOLUTE filepidl;
SFGAOF out;
std::wstring strtext = std::wstring(itemText.begin(), itemText.end());
//cout << " ";
//cout << *(strtext.c_str()) + " ";
HRESULT parse = SHParseDisplayName(strtext.c_str(), NULL, &filepidl, SFGAO_CANDELETE, &out);
if (filepidl != NULL) {
LPTSTR filePath = new TCHAR[MAX_PATH];
BOOL getPath = SHGetPathFromIDList(filepidl, filePath);
cout << *filePath ;
}
}
This is part of my code. I think there's something wrong with how I'm getting the index of the file because it keeps returning 0 but I've been hacking at this for days and am stuck. The MSDN documentation is confusing to me at best.
Any help or insight would be appreciated! I can't find any example code of this online. Thanks!
Using the listview directly like this is not a good idea because Explorer is free to implement the shell view in any way it wants and in Windows 7 and later a Explorer window no longer uses a listview, it uses a custom control by default!
If you only care about the display name and invoking the default action you can use UI Automation, it should work on other types of windows/controls as well, not just a shell file list.
If you need to know the full path and other details you can use the IShellWindows interface. Examples can be found on Raymond Chens blog here and here...
I want to be able to apply tranformations to Polydata but no matter how I try to do it, it just doesn't work.
Here is what I have for "drawing" my polydata in a class call Drawing.cpp:
Drawing.h
vtkSmartPointer<vtkPlane> clipPlane;
vtkSmartPointer<vtkImplicitPlaneRepresentation> planeRep;
vtkSmartPointer<vtkActor> actorPlaneSource;
vtkSmartPointer<vtkActor> mainActor;
vtkSmartPointer<vtkTransformPolyDataFilter> transformFilter;
vtkSmartPointer<vtkTransform> translation ;
vtkContextView* ctxView ;
vtkRenderWindow* win ;
vtkRenderer* ren ;
vtkCamera* cam ;
vtkSmartPointer<vtkPolyData> inputPolyData;
Then the read function is called and starts the rendering, here is the function in drawing.cpp:
void Drawing::read(){
std::string filename = BUNNY;
// Read all the data from the file
vtkSmartPointer<vtkXMLPolyDataReader> reader =vtkSmartPointer<vtkXMLPolyDataReader>::New();
reader->SetFileName(filename.c_str());
reader->Update();
inputPolyData = reader->GetOutput();
cout << "File Found and Loaded : " << filename << endl ;
vtkSmartPointer<vtkTransform> translation = vtkSmartPointer<vtkTransform>::New();
translation->Translate(0.3, -0.05, 0);
transformFilter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
//transformFilter->SetInputConnection(reader->GetOutputPort());
transformFilter->SetInputData(inputPolyData);
transformFilter->SetTransform(translation);
//transformFilter->Update();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(transformFilter->GetOutputPort());
mainActor = vtkSmartPointer<vtkActor>::New();
mainActor->SetMapper(mapper);
ren->AddActor(mainActor);
vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
iren->SetRenderWindow(win);
vtkInteractorStyleMultiTouchCamera *style =
vtkInteractorStyleMultiTouchCamera::New();
iren->SetInteractorStyle(style);
//Start the event loop
iren->Initialize();
iren->Start();
defineClipping();
win->PolygonSmoothingOn();
win->Render();
win->Start();
}
From this, I have an other thread running a server that gets messages and has a pointer to my drawing object and is supposed to call one of these three functions depending on the message it gets from its clients:
void Drawing::scale(float k){
vtkSmartPointer<vtkTransform> transform =vtkSmartPointer<vtkTransform>::New();
transform->Scale(5,1,1);
vtkSmartPointer<vtkTransformFilter> transformFilter = vtkSmartPointer<vtkTransformFilter>::New();
transformFilter->SetInputConnection(cone->GetOutputPort());
transformFilter->SetTransform(transform);
mapper->SetInputConnection(transformFilter->GetOutputPort());
ren->GetActiveCamera();
}
void Drawing::translate(float x, float y, float z){
cout << "Translate: " << x << " - " << " - " << y << " - " << z << endl ;
vtkSmartPointer<vtkTransform> transform1a = vtkSmartPointer<vtkTransform>::New();
//transform1a->Translate(x,y,z);
//transformFilter->SetTransform(transform1a);
//transformFilter->Update();
double* position = mainActor->GetPosition();
mainActor->SetPosition(position[0]+x,position[1]+y,position[2]+z);
}
void Drawing::rotate(float x, float y, float z){
cout << "Rotate: " << x << " - " << " - " << y << " - " << z << endl ;
vtkSmartPointer<vtkTransform> transform1a = vtkSmartPointer<vtkTransform>::New();
//transform1a->PostMultiply();
//transform1a->RotateX(x);
//transform1a->RotateY(y);
//transform1a->RotateZ(z);
//mainActor->SetUserTransform(transform1a);
mainActor->RotateWXYZ(20,1,0,0);
}
None of these functions work because nothing is changing in the rendering windows unless I click in the rendering window itself.
So I thought maybe I should try and add to every transformation functions: ctxView->Render();
But when I do I get:
Error the ressource is already busy.
I'm a newbie in VTK but I find it weird that I can't even do a simple transformation to an object. Would really like to get some help with that.
EDIT:
Ok so after hours of trying different things I have notices that if I comment out the line iren->Start(); my rotations and translations are called. However, the program closes as soon as there done and I cannot interact with my window anymore. Would you have some insights on that?
Thanks in advance.
Yes, I could try to give a little code that made rotations to a polydata, but I guess that is something different from your pipeline (I am using vtkImageReslice object as m_pReslice):
int nExtent[3];
double dSpacing[3];
double dOrigin[3];
m_pReader->GetOutput()->GetSpacing(dSpacing);
m_pReader->GetOutput()->GetOrigin(dOrigin);
m_pReader->GetOutput()->GetDimensions(nExtent);
double dCenter[3];
dCenter[0] = dOrigin[0] + dSpacing[0] * 0.5 * nExtent[0]; // nExtent[0] is width
dCenter[1] = dOrigin[1] + dSpacing[1] * 0.5 * nExtent[1]; // nExtent[1] is height
dCenter[2] = dOrigin[2] + dSpacing[2] * 0.5 * nExtent[2]; // nExtent[2] is depth
vtkSmartPointer<vtkTransform> pTransform = vtkSmartPointer<vtkTransform>::New();
pTransform->PreMultiply();
int nDirection = CDirectionDlg::GetDirection();
if(CDirectionDlg::DIR_AXIAL == nDirection)
{
pTransform->Translate(dCenter[0], 0, dCenter[2]);
pTransform->RotateY(180);
pTransform->Translate(-dCenter[0], 0, -dCenter[2]);
}
else
{
pTransform->Translate(dCenter[0], dCenter[1], 0);
pTransform->RotateZ(180);
pTransform->Translate(-dCenter[0], -dCenter[1], 0);
}
m_pReslice->SetResliceTransform(pTransform);
m_pReslice->SetInterpolationModeToLinear();
m_pReslice->Update();
Consider that another way to rotate an object in a view is to moving camera ... I hope it help you.
As flaviu2 wrote, you absolutely need to call
ren->Render();
after updating your vtkTransform. Renderers do not watch VTK objects that are being rendered to see if anything has been updated. You need to call the Render() member function explicitly.
Beware threading. It is possible to use threading, but most of VTK is not thread safe, and it is probably going to cause you some headaches. To separate this problem from potential problems caused by using different threads to update objects, I would try to get this working without threading, and update this question if you still encounter problems.
Since your problem is the interactor, try doing this hack. Waht it does is create a timer for the interactor that will help get out of the start blocking method :
class CommandSubclass2 : public vtkCommand
{
public:
vtkTypeMacro(CommandSubclass2, vtkCommand);
static CommandSubclass2 *New()
{
return new CommandSubclass2;
}
void Execute(vtkObject *vtkNotUsed(caller), unsigned long vtkNotUsed(eventId),
void *vtkNotUsed(callData))
{
std::cout << "timer callback" << std::endl;
renderWindowInteractor->ExitCallback();
}
};
// in your main
vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
iren->SetRenderWindow(win);
iren->CreateRepeatingTimer(1);
vtkSmartPointer<CommandSubclass2> timerCallback =
vtkSmartPointer<CommandSubclass2>::New();
iren->AddObserver ( vtkCommand::TimerEvent, timerCallback );
vtkInteractorStyleMultiTouchCamera *style =
vtkInteractorStyleMultiTouchCamera::New();
iren->SetInteractorStyle(style);
while(true)
{
iren->Start();
ren->Render();
}
Probably not the good way of doing it, but I don't know any other way to get out of the interactor blocking method start()
So thanks to the help of people here and some research with the code and documentation I've figured that this part in my code was responsible for nothing happening when trying to rotate/translate/scale my Polydata:
//Start the event loop
iren->Initialize();
iren->Start();
Indeed the start() method of the vtkRenderWindowInteractor is blocking and therefore no matter what I could call afterward was not processed. Getting rid of it allows me to call my transformation functions. Yet with the loss of the possible interaction with the data and the window closing right after every transformation is applied.
This code is for VLC Media Player. If I move the mouse in fullscreen, the message and the x,y coordinates get displayed. I want to display a message when I click (left or right) on fullscreen. How can I do this? I'm using Qt.
void FullscreenControllerWidget::mouseChanged( vout_thread_t *p_vout, int i_mousex, int i_mousey )
{
bool b_toShow;
/* FIXME - multiple vout (ie multiple mouse position ?) and thread safety if multiple vout ? */
qDebug() << "mouse moved"; //ajay
b_toShow = false;
if ((i_mouse_last_move_x == -1 || i_mouse_last_move_y == -1) ||
(abs( i_mouse_last_move_x - i_mousex ) > 2 ||
abs( i_mouse_last_move_y - i_mousey ) > 2 ))
{
i_mouse_last_move_x = i_mousex;
i_mouse_last_move_y = i_mousey;
qDebug() << "mouse move changed x:" << i_mouse_last_move_x; // ajay
qDebug() << "mouse move changed y:" << i_mouse_last_move_y; // ajay
b_toShow = true;
}
if (b_toShow)
{
/* Show event */
IMEvent *eShow = new IMEvent(FullscreenControlShow_Type, 0);
QApplication::postEvent(this, eShow);
/* Plan hide event */
IMEvent *eHide = new IMEvent(FullscreenControlPlanHide_Type, 0);
QApplication::postEvent(this, eHide);
}
}
There is a special event for mouse clicks.
http://developer.qt.nokia.com/doc/qt-4.8/qwidget.html#mousePressEvent
http://developer.qt.nokia.com/doc/qt-4.8/qwidget.html#mouseReleaseEvent
Did you try implementing those? Btw. mouseChanged is vlc-specific.