I am trying implement rviz2 plugin in ROS2. I have referred user guide from the rviz for the development. Currently there no tutorial available to develop rviz dockable panel in ROS2. Therefore I have referred MoveIt2 and Navigation 2 package for their rviz plugin implementation in ROS2. Here is my code.
demo_widget.h:
#ifndef DEMO_WIDGET_H
#define DEMO_WIDGET_H
#include <QWidget>
#include <memory>
#include <vector>
#include "ui_pointcloud_controller.h"
#ifndef Q_MOC_RUN
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/string.hpp>
#endif
namespace Ui {
class DemoWidgetUI;
}
namespace prc_demo_panel
{
class DemoWidget : public QWidget
{
Q_OBJECT
public:
DemoWidget(QWidget * parent = 0);
~DemoWidget() override;
public Q_SLOTS:
private Q_SLOTS:
protected:
std::unique_ptr<Ui::DemoWidgetUI> ui_;
private:
rclcpp::Node::SharedPtr _node;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr _publisher;
};
}
demo_widget.cpp:
#include <prc_demo_panel/demo_widget.h>
namespace prc_demo_panel
{
DemoWidget::DemoWidget(QWidget *parent): QWidget(parent), ui_(new Ui::DemoWidgetUI)
{
ui_->setupUi(this);
connect(ui_->pushButton_1, &QPushButton::clicked, this, &DemoWidget::buttonOne);
connect(ui_->pushButton_2, &QPushButton::clicked, this, &DemoWidget::buttonTwo);
auto options = rclcpp::NodeOptions().arguments({"--ros-args --remap __node:=dialog_action_client"});
_node = std::make_shared<rclcpp::Node>("_", options);
_publisher = _node->create_publisher<std_msgs::msg::String>("gui_control", 10);
}
}
demo_panel.h:
#ifndef DEMO_PANEL_H
#define DEMO_PANEL_H
#include <QVBoxLayout>
#include <rviz_common/panel.hpp>
#include <prc_demo_panel/demo_widget.h>
namespace prc_demo_panel
{
class Demo_widget;
class DemoPanel : public rviz_common::Panel
{
Q_OBJECT
public:
explicit DemoPanel(QWidget * parent = 0);
virtual ~DemoPanel();
void onInitialize() override;
void save(rviz_common::Config config) const override;
void load(const rviz_common::Config &conf) override;
private:
DemoWidget *_widget;
};
}
#endif // RVIZ_PANEL_H
demo_panel.cpp:
#include "prc_demo_panel/demo_panel.h"
#include <QVBoxLayout>
#include <memory>
#include <vector>
#include <utility>
#include <rviz_common/display_context.hpp>
namespace prc_demo_panel
{
DemoPanel::DemoPanel(QWidget * parent) : Panel(parent)
{
_widget = new DemoWidget(parent);
QVBoxLayout * layout = new QVBoxLayout;
layout->addWidget(_widget);
layout->setContentsMargins(10, 10, 10, 10);
setLayout(layout);
}
void DemoPanel::save(rviz_common::Config config) const
{
Panel::save(config);
}
void DemoPanel::load(const rviz_common::Config &conf)
{
Panel::load(conf);
}
void DemoPanel::onInitialize()
{
auto node = getDisplayContext()->getRosNodeAbstraction().lock()->get_raw_node();
}
}
#include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS(prc_demo_panel::DemoPanel, rviz_common::Panel)
CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project(prc_demo_panel)
.
.
.
# find dependencies
find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets Test Concurrent)
set (THIS_PACKAGE_INCLUDE_DEPENDS
rclcpp
class_loader
pluginlib
Qt5
rviz2
rviz_common
rviz_default_plugins
rviz_rendering
rviz_ogre_vendor
)
include_directories(
include
)
# I prefer the Qt signals and slots to avoid defining "emit", "slots",
# etc because they can conflict with boost signals, so define QT_NO_KEYWORDS here
# e.g. http://muddyazian.blogspot.de/2012/04/getting-qt-app-working-with-boost-using.html
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
#set(CMAKE_AUTORCC ON)
#add_definitions(-DQT_NO_KEYWORDS)
# Define source file
set(${PROJECT_NAME}_SRCS
src/demo_panel.cpp
src/demo_widget.cpp
#src/plugin_init.cpp
)
# Define header file
set(${PROJECT_NAME}_HDRS
include/${PROJECT_NAME}/demo_panel.h
include/${PROJECT_NAME}/demo_widget.h
)
# Define ui file
set(${PROJECT_NAME}_UIS
resource/pointcloud_controller.ui
)
message(STATUS "Generate header for ui with rviz2_QT_VERSION: ${rviz2_QT_VERSION}")
qt5_wrap_ui(${PROJECT_NAME}_UIS_H ${${PROJECT_NAME}_UIS})
foreach(header "${${PROJECT_NAME}_HDRS}")
qt5_wrap_cpp(${PROJECT_NAME}_MOCS ${header})
endforeach()
## Add library is needed in order to generate the header file from ui file.
add_library(${PROJECT_NAME} SHARED
${${PROJECT_NAME}_SRCS}
${${PROJECT_NAME}_UIS_H}
${${PROJECT_NAME}_MOCS}
)
ament_target_dependencies(${PROJECT_NAME} ${THIS_PACKAGE_INCLUDE_DEPENDS})
target_include_directories(${PROJECT_NAME} PUBLIC
${Qt5Widgets_INCLUDE_DIRS}
${OGRE_INCLUDE_DIRS}
)
target_link_libraries(${PROJECT_NAME} rviz_common::rviz_common)
# target_include_directories(${PROJECT_NAME} PUBLIC
# $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
# $<INSTALL_INTERFACE:include>
# )
target_compile_definitions(${PROJECT_NAME} PUBLIC "PLUGINLIB__DISABLE_BOOST_FUNCTIONS")
target_compile_definitions(${PROJECT_NAME} PRIVATE "RVIZ_DEFAULT_PLUGINS_BUILDING_LIBRARY")
pluginlib_export_plugin_description_file(rviz_common demo_plugin.xml)
install(
TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)
install(
DIRECTORY include/
DESTINATION include
)
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# uncomment the line when a copyright and license is not present in all source files
#set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# uncomment the line when this package is not in a git repo
#set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
ament_export_include_directories(include)
ament_export_libraries(${PROJECT_NAME})
ament_export_targets(${PROJECT_NAME} HAS_LIBRARY_TARGET)
ament_export_dependencies(${THIS_PACKAGE_INCLUDE_DEPENDS})
ament_package()
package.xml
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>prc_demo_panel</name>
<version>0.0.0</version>
<description>Point Cloud Resolution Control</description>
<maintainer email="vishnu.pbhat93#gmail.com">vishnu</maintainer>
<license>TODO: License declaration</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<build_depend>qtbase5-dev</build_depend>
<exec_depend>libqt5-core</exec_depend>
<exec_depend>libqt5-gui</exec_depend>
<exec_depend>libqt5-opengl</exec_depend>
<exec_depend>libqt5-widgets</exec_depend>
</package>
demo_plugin.xml:
<library path="/libprc_demo_panel" >
<class
name="prc_demo_panel/Demo Panel"
type="prc_demo_panel::DemoPanel"
base_class_type="rviz_common::Panel"
>
<description>
Point Cloud Resolution Control
</description>
</class>
</library>
This package can compile colcon build --symlink-install without any errors and rviz2 is able recognize the plugin. However when I try to add the plugin in rviz2 I am getting following error:
[ERROR] [1634722985.299621064] [rviz2]: PluginlibFactory: The plugin for class 'prc_demo_panel/Demo Panel' failed to load.
Error: Could not find library corresponding to plugin prc_demo_panel/Demo Panel. Make sure the plugin description XML file has the correct name of the library and that the library actually exists.
I am not able to determine what is a mistake that I am doing. I would really appreciate any help.
Thank you
Hey I am sure you have figured out the answer to this, just to make sure that others are able to find the answer easily here is what is causing the issue.
The causing of this error is usually the wrong library path. Library path in demo_plugin.xml should be changed to the ros package name of your ros package ( If you build the whole package as a library. ), such as <library path="prc_demo_panel" >. If your ros package has lots of sublibraries, you should change library name to the name of library which your panel lacated.
Related
I have a QObject derived class Expense that I use in QML like this.
// main.qml
Expense {
id: expenseManager
onExpenseCreated: {
// Do something
}
}
The expense class has no UI components, it has some basic Signal and Slots for API communications.
// expense.h
#ifndef EXPENSE_H
#define EXPENSE_H
#include <QObject>
#include <QString>
#include "service.h"
class Expense : public QObject
{
Q_OBJECT
private:
Service service;
void networkError();
bool buttonLock = false;
public:
explicit Expense(QObject *parent = nullptr);
public slots:
void createInvoice(QString item, float amount);
signals:
void expenseCreated();
};
#endif // EXPENSE_H
I have used qmlRegisterType() for registering Expense type in QML. Below is how my main() looks like.
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
......
qmlRegisterType<Expense>("com.kadbyte.expense", 1, 0, "Expense");
........
return app.exec();
}
Everything working perfectly as it used to. But recently I have upgraded my project to QT6 with CMake as the build tool instead of QMake. In the docs I saw that we can use qt_add_qml_module command in CMakeList.txt to register C++ Classes instead of qmlRegisterType(), by adding QML_ELEMENT macro to the QObject class.
But I can't understand how to do this, the documentation doesn't make sense as it uses qmake example (Link to docs) instead of CMake. Below is my CMakeLists.txt file
cmake_minimum_required(VERSION 3.16)
project(Udyan VERSION 0.1 LANGUAGES CXX)
set(CMAKE_AUTOMOC ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 6.2 COMPONENTS Quick REQUIRED)
qt_add_executable(appUdyan
main.cpp
expense.h expense.cpp
)
qt_add_qml_module(appUdyan
URI Udyan
VERSION 1.0
QML_FILES qml/main.qml
)
set_target_properties(appUdyan PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
target_compile_definitions(appUdyan
PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
target_link_libraries(appUdyan
PRIVATE Qt6::Quick)
So how to use qt_add_qml_module to registering QObject class to use in QML?
Note: All the example I have given above is just an MRE and not my complete code.
You just need to add QML_ELEMENT to your QObject-derived Expense class's header and make sure you have moc enabled in your CMakeLists.txt. In application case it doesn't matter if the expense.h/cpp sources are included via qt_add_executable or qt_add_qml_module. I think it's clearer to add them to qt_add_qml_module SOURCES. Then you just import module URI in you QML file. In the example below I'm printing out property value from Expense object in QML.
CMakeLists.txt
set(CMAKE_AUTOMOC ON)
qt_add_qml_module(appUdyan
URI udyan
VERSION 1.0
QML_FILES
main.qml
SOURCES
expense.h
expense.cpp
)
C++
#include <QObject>
#include <QtQml/qqmlregistration.h>
class Expense : public QObject
{
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(int value READ value NOTIFY valueChanged)
public:
explicit Expense(QObject *parent = nullptr);
int value() const;
signals:
void valueChanged();
private:
int m_value {5};
};
QML:
import QtQuick
import udyan
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Expense {
id: expense
Component.onCompleted: console.log(expense.value)
}
}
I'm trying to build a simple qt project with CMake, which contains main.cxx, MainWindow.cxx and MainWindow.hxx. When I try to make install it says fatal error: 'QMainWindow' file not found, but I do added Widgets in the CMakelists.txt.
Here are the codes:
main.cxx:
#include <QApplication>
#include "MainWindow.h"
int main(int argc, char** argv){
QApplication GUI(argc, argv);
MainWindow window;
window.shou();
return GUI.exec();
}
MainWindow.cxx
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
}
MainWindow::~MainWindow()
{
}
MainWindow.hxx
#ifndef MAINWINDOW_HXX_
#define MAINWINDOW_HXX_
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent =0);
~MainWindow();
};
#endif
CMakeLists.txt
cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
project(Gui_Window)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
find_package(Qt6 COMPONENTS Widgets REQUIRED)
add_library(MAINWINDOW ${CMAKE_CURRENT_SOURCE_DIR}/src/MainWindow.cxx)
add_executable(Gui_Window ${CMAKE_CURRENT_SOURCE_DIR}/app/main.cxx)
target_link_libraries(Gui_Window PUBLIC Qt6::Widgets
MAINWINDOW
)
install(TARGETS Gui_Window DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
What should be the problem?
Your MainWindow.cxx file should be included in your CMakeLists.txt file like this:
set(PROJECT_SOURCES MainWindow.cxx)
You'd want main in there too.
As an aside, it's much easier to use Qt Creator and let it generate the CMakeLists.txt file for you.
I have 3 files in my c++/qt project and I'm using CMake. I'm trying to compile it Here are some code:
CMakeLists contains:
cmake_minimum_required(VERSION 3.8)
project(untitled)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_PREFIX_PATH /Users/username/Qt/5.9.2/clang_64/)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
find_package(Qt5Core)
find_package(Qt5Network)
set(SOURCE_FILES main.cpp server.cpp)
add_executable(untitled ${SOURCE_FILES})
target_link_libraries(${PROJECT_NAME} Qt5::Core)
target_link_libraries(${PROJECT_NAME} Qt5::Network)
Main.cpp contains:
#include <iostream>
#include <QCoreApplication>
#include <QtDebug>
#include "server.cpp"
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
MyTcpServer server;
return app.exec();
}
and finally server.cpp contains:
#include <QObject>
#include <QTcpSocket>
#include <QTcpServer>
#include "server.moc"
class MyTcpServer : public QObject
{
Q_OBJECT
public:
explicit MyTcpServer(QObject *parent = 0);
public slots:
void slotNewConnection();
void slotServerRead();
void slotClientDisconnected();
private:
QTcpServer * mTcpServer;
QTcpSocket * mTcpSocket;
};
MyTcpServer::MyTcpServer(QObject *parent) : QObject(parent)
{
...
}
void MyTcpServer::slotNewConnection()
{
...
}
void MyTcpServer::slotServerRead()
{
...
}
void MyTcpServer::slotClientDisconnected()
{
mTcpSocket->close();
}
I'm trying to compile my project with CMake, and when I run the CMake, I have this problems :
duplicate symbol __ZN11MyTcpServer18qt_static_metacallEP7QObjectN11QMetaObject4CallEiPPv in:
CMakeFiles/untitled.dir/main.cpp.o
CMakeFiles/untitled.dir/server.cpp.o
...
duplicate symbol __ZN11MyTcpServer16staticMetaObjectE in:
CMakeFiles/untitled.dir/main.cpp.o
CMakeFiles/untitled.dir/server.cpp.o
ld: 13 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Telling me that there is a duplicate symbol.
How to resolve this?
It is better not to use #include for .cpp files. It is good practice to split definition and declaration into different files.
(One exception from this is the private declaration in case of PIMPL pattern.)
In case you want to avoid the split because you have only small pieces of code use a header file and implement your methods within the definition of the class.
In case a library is implemented: Do not install the header file in case your class must not accessible from outside.
The simple fix for your case would be fo#include "server.cpp" from your cpp as mentioned in comments (it is rarely needs to be done and virtually never is a good thing).
And the second thing would be to move the #include "server.moc" line to the end of the cpp file. This is important because this file contains implementation of some member functions injected with Q_OBJECT and the class needs to be defined before implementing member functions outside of its body.
This my project structure:
main
|
--src
|
--feed.h
--feed.cc
--other files
--CMakeLists2.txt
--test
|
--test.cpp
--CMakeLists3.txt
CMakeLists1.txt
CMakeLists1.txt
cmake_minimum_required (VERSION 2.8.11)
project (Feedparser)
set(CMAKE_MODULE_PATH cmake)
find_package(PTHREAD REQUIRED)
find_package(CURL REQUIRED)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 ")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x ")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
add_subdirectory (src)
add_subdirectory (test)
CMakeLists2.txt
cmake_minimum_required (VERSION 2.8.11)
add_library (Feedparser news.h xml2json.hpp jsonxx.cc curler.cc feed.cc )
target_link_libraries(Feedparser pthread)
target_link_libraries(Feedparser curl)
install(TARGETS Feedparser
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION /usr/lib)
install(FILES "feed.h" DESTINATION /usr/include )
target_include_directories (Feedparser PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
CMakeLists3.txt
cmake_minimum_required (VERSION 2.8.11)
add_executable(Feedtest test.cc)
target_link_libraries (Feedtest LINK_PUBLIC Feedparser)
Here is my Header file.
feed.h
#include "news.h"
#include "curler.cc"
#include "jsonxx.h"
#include "jsonxx.cc"
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <thread>
#include <stdio.h>
using namespace std;
using namespace jsonxx;
class feed{
map <string,string> info;
std::map<int, Object> items;
string url;
news News;
Object *item;
void strip_items();
public:
Object json;
feed(string url);
void create(string url){
this->url = url;
}
feed(){}
string get_topic(){
return info["title"];
}
bool fetch();
bool fetch_data();
bool parse();
string get_url(){
return url;
}
string get_item_title(int index){
return News.title[index];
}
string get_item_img(int index){
return News.image[index];
}
string get_item_link(int index){
return News.link[index];
}
int get_total(){
return News.num_item;
}
struct news get_news(){
return News;
}
};
Should I include feed.h in feed.cc and compile and how does the compiler directly link .h files with the .cxx files in archives?
How do i write a cmake script for installing this library?
Where is my mistake?
C++'s building process consists of 2 stages:
Compilation: The compiler runs on every source (.cc) file, generating an intermidiate binary.
Linking: The linker runs on every intermidiate binary, matching declarations with definitions.
Finally, it combines all of them to make the final binary.
With this in mind, you need to make sure the compiler doesn't come across something that it doesn't know about. That's why you include headers (.h).
The linker should be fed with everything the compiler creates.
I have two functions. In one function, i have a QImage and then i want to pass that QImage to another function. Both the function have different Arguments. Please tell me how can i do it?
CMakeLists.txt
cmake_minimum_required(VERSION 2.4.6)
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
rosbuild_init()
# Qt #####################################################
find_package(Qt4 REQUIRED)
set( QT_USE_QTGUI TRUE )
include(${QT_USE_FILE})
add_definitions (-DQT_NO_KEYWORDS)
# All source files
set(SELECTION_INTERFACE_SOURCE_CPP
src/SelectionInterface.cpp)
# All header files that use Qt Keywords (e.g. OBJECT)
set(SELECTION_INTERFACE_MOC_H
src/SelectionInterface.h
)
# Wrap for MOC
qt4_wrap_ui (SELECTION_INTERFACE_UI_H ${SELECTION_INTERFACE_UI})
qt4_wrap_cpp(SELECTION_INTERFACE_MOC ${SELECTION_INTERFACE_MOC_H})
rosbuild_add_library (selection_interface_lib
${SELECTION_INTERFACE_SOURCE_CPP}
${SELECTION_INTERFACE_MOC})
#set the default path for built executables to the "bin" directory
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
#set the default path for built libraries to the "lib" directory
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
rosbuild_add_executable(newtest_node src/SelectionInterface.cpp)
target_link_libraries (newtest_node selection_interface_lib ${QT_LIBRARIES})
Makefile
include $(shell rospack find mk)/cmake.mk
manifest
<package>
<description brief="newTestCode">
newTestCode
</description>
<author>admin</author>
<license>BSD</license>
<review status="unreviewed" notes=""/>
<url>http://ros.org/wiki/newTestCode</url>
<depend package="roscpp"/>
<depend package="sensor_msgs"/>
<depend package="std_msgs"/>
</package>
SelectionInterface.h
#ifndef SELECTION_INTERFACE_H
#define SELECTION_INTERFACE_H
#include <QApplication>
#include <QtGui/QWidget>
#include <QtGui/QMenu>
#include <QtGui/QAction>
#include <QMainWindow>
#include <QDebug>
#include <QLabel>
#include <QGraphicsPixmapItem>
class Image:public QMainWindow
{
Q_OBJECT
public:
void getImage();
void displayImage();
QImage tempImage;
};
#endif
SelectionInterface.cpp
#include "SelectionInterface.h"
void Image::getImage()
{
QImage myImage("/home/usr/Pictures/image.jpg");
qDebug() << myImage.height();
tempImage= myImage.copy();
}
void Image::displayImage()
{
QImage finalImage = tempImage;
qDebug()<<finalImage.height();
}
int main (int argc, char** argv)
{
QApplication app(argc, argv);
Image object;
object.getImage();
object.displayImage();
object.show();
return app.exec();
}
First of all, it is better that you use the term methods rather than functions, because these are class members and you will find most people calling these methods out there. Namely, these are members of your Image class.
You can use a member variable for it inside the Image class, which is accessible inside the first method as well as second.
class member
#include <QApplication>
#include <QMainWindow>
#include <QImage>
#include <QDebug>
class Image : public QMainWindow
{
Q_OBJECT
public:
void getImage() {
QImage myImage("/home/lpapp/Downloads/android.png");
qDebug() << myImage.height();
tempImage= myImage.copy();
}
void displayImage() {
QImage finalImage = tempImage;
qDebug() << finalImage.height();
}
private:
QImage tempImage;
};
#include "main.moc"
int main (int argc, char** argv)
{
QApplication app(argc, argv);
Image object;
object.getImage();
object.displayImage();
object.show();
return app.exec();
}
This should print out the same height, to make a very quick verification. You can find the command below, on my system, as to how to build and run this code. You need to generate the moc file, and then supply the include paths and libraries for the build and then, finally, run the application.
moc-qt5 -o main.moc main.cpp && g++ -I/usr/include/qt/QtWidgets -I/usr/include/qt/QtGui -I/usr/include/qt/QtCore -I/usr/include/qt -fPIC -lQt5Core -lQt5Widgets -lQt5Gui main.cpp && ./a.out
Output:
900
900
Although, depending on your use case, copy-on-write (COW) might not be sufficient enough, and you will want to use a pointer member to avoid the costly operation.
The documentation can be found here for the copy method; it will copy the whole, by default, if you do not specify the sub-area.
You can also use a static variable inside the same file that you set in method 1, and access in method 2. Note, you should define the static, in that case, outside the class to get a different approach. This is probably less frequently used than the class member, so I would prefer that.
You could probably also set the image on an external class, or variable, and then access. This all depends a lot on your particular case. This is broad question.
You could always use a QPainter as well, to draw the "source" into the "destination" with drawImage().