I have used Cinder about few weeks and i have some problem.
I am using method "drag-and-drop" in my program :
void TutorialApp::fileDrop(FileDropEvent drop){ /// drop are images
for(size_t i=0; i<drop.getNumFiles();++i){
Vertex imageVertex = Vertex((Vec2i(drop.getPos().x, drop.getPos().y+200)));
imageVertex.path = drop.getFiles()[i];
and next my step is draw Vertex with associeted image. So that is question: how to add resources in this case, or maybe there is more easy solution? Thank
Straight to the point:
First of all,you want to keep images (i.e gl::Texture) in your objects, that you want to draw. So in your class Vertex, add this gl::Texture as member. And then I suggest to use this function to load image and edit constructor, to take gl::Texture as parameter.
So you end up with something like this:
class testVertex
{
public:
testVertex(Vec2i _pos, gl::Texture image);
void draw(){
gl::draw(texture, pos);
}
private:
gl::Texture texture;
Vec2i pos;
};
///constructor
testVertex::testVertex(Vec2i _pos, gl::Texture image)
{
pos = _pos;
texture = image;
}
class BasicApp : public AppNative {
public:
void setup();
void mouseMove( MouseEvent event );
void mouseUp( MouseEvent event );
void keyUp(KeyEvent event);
void fileDrop(FileDropEvent event);
void update();
void draw();
//// create container for testVertex
vector <testVertex> mVertices;
}
/// To load images via drop...
void BasicApp::fileDrop(FileDropEvent event){
gl::Texture fileTexture = loadImage(event.getFile(0));
mVertices.push_back(testVertex(Vec2i(event.getX(), event.getY()), fileTexture));
}
/// To draw images...
void BasicApp::draw(){
for (int i = 0; i < mVertices.size(); i++)
{
mVertices[i].draw();
}
}
///
Related
My program consists of two functions: first a user clicks a button (btn_image) to upload an image from desktop and it displays on the label (lbl_image). Secondly, I push another button (cnv_image) in order to change the colors of that uploaded image to black and white.
I have managed to implement the first function: the image chosen by a user successfully displays. However, I am confused how to convert that image to b&w. I wrote a function that is triggered after clicking the cnv_image button, but the problem is to refer to that uploaded image. So, when I click cnv_image buttom the uploaded image simply disappears.
I tried to use image.load (ui->lbl_image) to refer to the label which contains the image but it shows a mistake.
How can I implement my second function?
void MainWindow::on_btn_image_clicked()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Choose"), "", tr("Images (*.png *.jpg *jpeg)"));
if (QString::compare(fileName, QString()) != 0) {
QImage image;
bool valid = image.load(fileName);
if (valid) {
ui->lbl_image->setPixmap(QPixmap::fromImage(image));
}
}
}
void MainWindow::on_cnv_image_clicked()
{
QImage image;
image.load(ui->lbl_image);
QSize sizeImage = image.size();
int width = sizeImage.width(), height = sizeImage.height();
QRgb color;
for (int f1=0; f1<width; f1++) {
for (int f2=0; f2<height; f2++) {
int gray = qGray(color);
image.setPixel(f1, f2, qRgb(gray, gray, gray));
}
}
ui->lbl_image->setPixmap(QPixmap::fromImage(image));
}
I update your code, I add QImage image; as private member of MainWindow class so In mainwindow.h :
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui
{
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow: public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_btn_image_clicked();
void on_cnv_image_clicked();
private:
Ui::MainWindow *ui;
QImage image;
};
#endif // MAINWINDOW_H
and in on_cnv_image_clicked function
void MainWindow::on_cnv_image_clicked()
{
QSize sizeImage = image.size();
int width = sizeImage.width(), height = sizeImage.height();
QRgb color;
int value;
for (int f1 = 0; f1 < width; f1++)
{
for (int f2 = 0; f2 < height; f2++)
{
color = image.pixel(f1, f2);
int gray = (qRed(color) + qGreen(color) + qBlue(color)) / 3;
image.setPixel(f1, f2, qRgb(gray, gray, gray));
}
}
ui->lbl_image->setPixmap(QPixmap::fromImage(image));
ui->lbl_image->setScaledContents(true);
}
Result :
Welcome to Stackoverflow!
First of all, it's a good idea to keep a copy of the QImage in your class when you load it. It helps to avoid extra conversions from QPixmap to QImage in next steps. I'll skip it because it's out of the scope of your question.
You can use QImage::convertTo to convert the format of a QImage in place. It means that, it does not create a new QImage. As per documentation it may detach the QImage. You can read more about Implicit Sharing if you are interested.
So, the implementation should be something like:
void MainWindow::on_cnv_image_clicked()
{
QImage image = ui->lbl_image->pixmap().toImage();
image.convertTo(QImage::Format_Grayscale8);
ui->lbl_image->setPixmap(QPixmap::fromImage(image));
}
Take a look at the list of QImage::Formats to evaluate other grayscale/mono options.
here is a code snippet from my Image class:
class Image{
public int width;
public int height;
public PImage img;
Image(PApplet parent){
width = 512;
height = 512;
img = new PImage();
img = parent.loadImage("test.jpg");
img.resize(width, height);
}
}
I draw it in the main file in such a way:
image(image.img, 287, 280);
I'd like to choose the image having clicked it:
void mousePressed() {
if (gui.btnOver1) {
selectInput("Choose file:", "fileSelected");
}
}
However, I don't know how to use this function in an OOP way:
void fileSelected(File selection) {
if (selection == null) {
println("Window was closed or the user hit cancel.");
} else {
img = loadImage(selection.getAbsolutePath());
img.loadPixels();
}
}
Thanks for help.
what about adding a method to your class like:
class Image{
public int width;
public int height;
public PImage img;
Image(PApplet parent){
width = 512;
height = 512;
img = new PImage();
img = parent.loadImage("test.jpg");
img.resize(width, height);
}
public void loadNew(path){
img = loadImage(path);
// I don't think you need to .updatePixels() after .loadImage()
}
}
Then you use it like that:
void fileSelected(File selection) {
if (selection == null) {
println("Window was closed or the user hit cancel.");
} else {
// assuming you have an 'image' object of the type Image
image.loadNew(selection.getAbsolutePath());
}
}
Note:
It's been a while since I wrote my last line of Processing code and it may be a bit wrong, but it should answer your question
You could even have a function to draw the Image object, rather than calling the property imgof your image,
like that:
// a method of your class
public void draw(int x, int y){
image(img, x, y);
}
and then inside the main draw() you will call
// always your image object here
image.draw(20, 34);
I hope it helps!
Every time I repaint on the QWidget it gets repainted and deletes the previous paint. How can I save the previous state while performing repainting?
You have to do it explicitly. One way would be to paint on a QImage, and then in the paintEvent simply blit the contents to the widget.
A much simpler approach is to store all the graphic primitives in a container of some sort, and paint them all as needed. Qt provides just such a container: QPicture is a graphic metafile that stores graphical operations for later replay.
For example:
class PicLabel : public QLabel {
QPicture m_picture;
public:
PicLabel(const QString & text, QWidget * parent = 0) :
QLabel(text, parent) {}
PicLabel(QWidget * parent = 0) : QLabel(parent) {}
void addPoint(const QPointF & point) {
QPainter p(&m_picture);
p.drawPoint(point);
update();
}
void addLine(const QPointF & start, const QPointF & end) {
QPainter p(&m_picture);
p.drawLine(start, end);
update();
}
void clear() {
std::swap(m_picture, QPicture());
update();
}
protected:
void paintEvent(QPaintEvent * event) Q_DECL_OVERRIDE {
QLabel::paintEvent(event);
QPainter p(this);
p.drawPicture(0, 0, m_picture);
}
};
I would like to load and draw multiple/all images from a directory in Processing.
I cant find a way to extend the one image example:
PImage a;
void setup() {
size(800,800);
background(127);
a = loadImage("a/1.jpg");
noLoop();
}
void draw(){
image(a,random(300),random(300),a.width/2, a.height/2);
}
to multiple images.
Is there a simple way to achieve this?
Thank you very much.
I'm sure there are more elegant ways to do it, but wouldn't something as simple as this work?
PImage a;
Pimage b;
void setup() {
size(800,800);
background(127);
a = loadImage("a/1.jpg");
b = loadImage("b/1.jpg");
noLoop();
}
void draw(){
image(a,random(300),random(300),a.width/2, a.height/2);
image(b,random(300),random(300),b.width/2, b.height/2);
}
You can find an example of listing a directories here: http://processing.org/learning/topics/directorylist.html. The reference section for loops is here: http://processing.org/reference/loop_.html.
Imagine u have a known number of images (n) called 0.jpg, 1.jpg, 2.jpg..., then u can do sth like this:
PImage[] fragment;
int n=3;
void setup() {
size(400, 400);
fragment=new PImage[n];
for(int i=0;i<fragment.length;i++){
fragment[i]=loadImage(str(i) + ".jpg");
}
}
void draw(){
for(int i=0;i<fragment.length;i++){
image(fragment[i],20*i,20*i);
}
}
I am trying to do a chess game. So I want to move the chess coin picture when the user clicks and drags the coin.
Which class I have to use
update
At last I am just editing the puzzle code which is given in drag and drop examples. Thereby I am trying to know the functions. But Still I am not getting certain things. I am executing the code below but the picture is not moving. And when I am closing I am getting a question from the OS(Windows XP), that there is an unhandled win32 exception in my program, so whether you want to debug or not. Here the code
#include<QApplication>
#include<QMainWindow>
#include<QWidget>
#include<QMenu>
#include<QMenuBar>
#include<QPainter>
#include<QFrame>
#include<QHBoxLayout>
#include<QScrollBar>
#include<QLabel>
#include<QScrollArea>
#include<QListWidgetItem>
#include<QByteArray>
#include<QDataStream>
#include<QMimeData>
#include<QDrag>
#include<QMouseEvent>
#include<iostream>
using namespace std;
class MyWindow:public QMainWindow
{
public:
MyWindow();
};
class MyWidget:public QWidget
{
QPixmap picture;
QPixmap temp;
public:
MyWidget();
void paintEvent(QPaintEvent * event);
void mousePressEvent(QMouseEvent * mouse);
void dragEnterEvent(QDragEnterEvent * dragEnterEvent);
void dragLeaveEvent(QDragLeaveEvent * event);
void dragMoveEvent(QDragMoveEvent * event);
void dropEvent(QDropEvent * event);
};
int main(int argc,char *argv[])
{
Q_INIT_RESOURCE(puzzle);
QApplication app(argc,argv);
MyWindow mainWindow;
mainWindow.show();
return app.exec();
}
MyWindow::MyWindow():QMainWindow()
{
setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding));
QMenu * fileMenu=menuBar()->addMenu(QObject::tr("Options"));
QAction * restartAction = fileMenu->addAction(tr("NewGame"));
QAction * exitAction = fileMenu->addAction(tr("Exit"));
exitAction->setShortcuts(QKeySequence::Quit);
QWidget * tempWidget=new MyWidget();
QFrame * newFrame=new QFrame();
QHBoxLayout * horizontal= new QHBoxLayout(newFrame);
horizontal->addWidget(tempWidget);
setCentralWidget(newFrame);
}
MyWidget::MyWidget():QWidget()
{
setMinimumSize(10,10);
setMaximumSize(1000,1000);
}
void MyWidget::dragEnterEvent(QDragEnterEvent * dragEnterEvent)
{
if(dragEnterEvent->mimeData()->hasFormat("chess"))
dragEnterEvent->accept();
else
dragEnterEvent->ignore();
}
void MyWidget::dragLeaveEvent(QDragLeaveEvent *event)
{
update(QRect(0,0,picture.width(),picture.height()));
event->accept();
}
void MyWidget::dragMoveEvent(QDragMoveEvent *event)
{
if(event->mimeData()->hasFormat("chess"))
{
event->setDropAction(Qt::MoveAction);
event->accept();
}
else
event->ignore();
update(QRect(0,0,picture.width(),picture.height()));
}
void MyWidget::dropEvent(QDropEvent *event)
{
if(event->mimeData()->hasFormat("chess"))
{
event->setDropAction(Qt::MoveAction);
event->accept();
}
else
event->ignore();
update(QRect(0,0,picture.width(),picture.height()));
}
void MyWidget::paintEvent(QPaintEvent * event)
{
QPainter painter;
painter.begin(this);
picture=QPixmap("C:\\Board").scaled(600,600,Qt::KeepAspectRatioByExpanding,Qt::SmoothTransformation);
setFixedSize(picture.size());
painter.drawPixmap(0,0,picture.height(),picture.width(),picture);
temp=QPixmap("C:\\blackElephant").scaled(60,30,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
painter.drawPixmap(0,0,temp.height(),temp.width(),temp);
painter.end();
}
void MyWidget::mousePressEvent(QMouseEvent * mouse)
{
QByteArray array;
QDataStream stream(&array,QIODevice::WriteOnly);
stream << temp;
QMimeData mimeData;
mimeData.setData("chess",array);
QDrag * newDrag=new QDrag(this);
newDrag->setMimeData(&mimeData);
newDrag->setHotSpot(mouse->pos());
newDrag->setPixmap(temp);
update(QRect(0,0,picture.width(),picture.height()));
}
any help will be appreciated.
Have a look at QGraphicsView, it gives you a canvas to put items on, and even can do animations. Should make things a lot easier than painting pixmaps by hand.
For drag and drop, you have to use QDrag class (check Qt examples on drag for details). QDrag class has a property called pixmap (pixmap(), setPixmap()) that can be used to set the image associated with the drag operation.