How can I draw Fibonacci Retracement from one Zigzag point to the other - algorithmic-trading

I have made an EA that simply displays the ZigZag indicator line. Please see the code below. I would like to add a Fibonacci retracement (as seen in the image link below) from the drawn one end to the other of the ZigZag in the opposite direction. How can I draw this Fibonacci retracement programmatically and access the values at 100.0, 61.8 and so on?
ZigZagWithFibonacci
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\AccountInfo.mqh>
#include <Trade\OrderInfo.mqh>
#include <Expert\Money\MoneyFixedMargin.mqh>
CPositionInfo m_position; // trade position object
CTrade m_trade; // trading object
CSymbolInfo m_symbol; // symbol info object
CAccountInfo m_account; // account info wrapper
COrderInfo m_order; // pending orders object
CMoneyFixedMargin *m_money;
int handle_iCustom; // variable for storing the handle of the iCustom indicator
int OnInit()
{
//---
//---
//--- create handle of the indicator iCustom
handle_iCustom=iCustom(m_symbol.Name(),Period(),"Examples\\ZigZag");
//--- if the handle is not created
if(handle_iCustom==INVALID_HANDLE)
{
//--- tell about the failure and output the error code
PrintFormat("Failed to create handle of the iCustom indicator for the symbol %s/%s, error code %d",
m_symbol.Name(),
EnumToString(Period()),
GetLastError());
if(m_money!=NULL)
delete m_money;
//--- the indicator is stopped early
return(INIT_FAILED);
}
//---
// ---
ChartIndicatorAdd ( 0 , 0 , handle_iCustom);
// ---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
}
//+------------------------------------------------------------------+

Related

How to get pixel data out of an IDXGISurface created with GPU access only?

In broad strokes, what I'm trying to accomplish is capture (part of) the screen and transform the capture into a digital image format. The following steps outline what I believe to be the solution:
Set up a Direct3D11CaptureFramePool and subscribe to its FrameArrived event
Gain access to the pixel data in the FrameArrived event delegate
Pass image data into the Windows Imaging Component to do the encoding
My issue is with step 2: While I can get the captured frame, gaining CPU read access to the surface fails. This my FrameArrived event delegate implementation (full repro below):
void on_frame_arrived(Direct3D11CaptureFramePool const& frame_pool, winrt::Windows::Foundation::IInspectable const&)
{
if (auto const frame = frame_pool.TryGetNextFrame())
{
if (auto const surface = frame.Surface())
{
if (auto const interop = surface.as<::Windows::Graphics::DirectX::Direct3D11::IDirect3DDxgiInterfaceAccess>())
{
com_ptr<IDXGISurface> dxgi_surface { nullptr };
check_hresult(interop->GetInterface(IID_PPV_ARGS(&dxgi_surface)));
DXGI_MAPPED_RECT info = {};
// Fails with `E_INVALIDARG`
check_hresult(dxgi_surface->Map(&info, DXGI_MAP_READ));
}
}
}
}
The Map() call is failing with E_INVALIDARG, and the debug layer offers additional, helpful error diagnostics:
DXGI ERROR: IDXGISurface::Map: This object was not created with CPUAccess flags that allow CPU access. [ MISCELLANEOUS ERROR #42: ]
So, now that I know what's wrong, how do I solve this? Specifically, how do I pull the pixel data out of a surface created with GPU access only?
Following is a full repro. It was originally created using the "Windows Console Application (C++/WinRT)" project template. The only change applied is "Precompiled Header: Use (/Yu)" → "Precompiled Header: Not Using Precompiled Headers", to keep this a single file.
It creates a command line application that expects a window handle as its only argument, in decimal, hex, or octal.
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Graphics.Capture.h>
#include <winrt/Windows.Graphics.DirectX.Direct3D11.h>
#include <winrt/Windows.Graphics.DirectX.h>
#include <Windows.Graphics.Capture.Interop.h>
#include <windows.graphics.capture.h>
#include <windows.graphics.directx.direct3d11.interop.h>
#include <Windows.h>
#include <d3d11.h>
#include <dxgi.h>
#include <cstdint>
#include <stdio.h>
#include <string>
using namespace winrt;
using namespace winrt::Windows::Graphics::Capture;
using namespace winrt::Windows::Graphics::DirectX;
using namespace winrt::Windows::Graphics::DirectX::Direct3D11;
void on_frame_arrived(Direct3D11CaptureFramePool const& frame_pool, winrt::Windows::Foundation::IInspectable const&)
{
wprintf(L"Frame arrived.\n");
if (auto const frame = frame_pool.TryGetNextFrame())
{
if (auto const surface = frame.Surface())
{
if (auto const interop = surface.as<::Windows::Graphics::DirectX::Direct3D11::IDirect3DDxgiInterfaceAccess>())
{
com_ptr<IDXGISurface> dxgi_surface { nullptr };
check_hresult(interop->GetInterface(IID_PPV_ARGS(&dxgi_surface)));
DXGI_MAPPED_RECT info = {};
// This is failing with `E_INVALIDARG`
check_hresult(dxgi_surface->Map(&info, DXGI_MAP_READ));
}
}
}
}
int wmain(int argc, wchar_t const* argv[])
{
init_apartment(apartment_type::single_threaded);
// Validate input
if (argc != 2)
{
wprintf(L"Usage: %s <HWND>\n", argv[0]);
return 1;
}
auto const target = reinterpret_cast<HWND>(static_cast<intptr_t>(std::stoi(argv[1], nullptr, 0)));
// Get `GraphicsCaptureItem` for `HWND`
auto interop = get_activation_factory<GraphicsCaptureItem, IGraphicsCaptureItemInterop>();
::ABI::Windows::Graphics::Capture::IGraphicsCaptureItem* capture_item_abi { nullptr };
check_hresult(interop->CreateForWindow(target, IID_PPV_ARGS(&capture_item_abi)));
// Move raw pointer into smart pointer
GraphicsCaptureItem const capture_item { capture_item_abi, take_ownership_from_abi };
// Create D3D device and request the `IDXGIDevice` interface...
com_ptr<ID3D11Device> device = { nullptr };
check_hresult(::D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr,
D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_DEBUG, nullptr, 0,
D3D11_SDK_VERSION, device.put(), nullptr, nullptr));
auto dxgi_device = device.as<IDXGIDevice>();
// ... so that we can get an `IDirect3DDevice` (the capture frame pool
// speaks WinRT only)
com_ptr<IInspectable> d3d_device_interop { nullptr };
check_hresult(::CreateDirect3D11DeviceFromDXGIDevice(dxgi_device.get(), d3d_device_interop.put()));
auto d3d_device = d3d_device_interop.as<IDirect3DDevice>();
// Create a capture frame pool and capture session
auto const pool = Direct3D11CaptureFramePool::Create(d3d_device, DirectXPixelFormat::B8G8R8A8UIntNormalized, 1,
capture_item.Size());
auto const session = pool.CreateCaptureSession(capture_item);
[[maybe_unused]] auto const event_guard = pool.FrameArrived(auto_revoke, &on_frame_arrived);
// Start capturing
session.StartCapture();
// Have the system spin up a message loop for us
::MessageBoxW(nullptr, L"Stop capturing", L"Capturing...", MB_OK);
}
You must create a 2D texture that can be accessed by the CPU and copy the source frame into this 2D texture, which you can then Map. For example:
void on_frame_arrived(Direct3D11CaptureFramePool const& frame_pool, winrt::Windows::Foundation::IInspectable const&)
{
wprintf(L"Frame arrived.\n");
if (auto const frame = frame_pool.TryGetNextFrame())
{
if (auto const surface = frame.Surface())
{
if (auto const interop = surface.as<::Windows::Graphics::DirectX::Direct3D11::IDirect3DDxgiInterfaceAccess>())
{
com_ptr<IDXGISurface> surface;
check_hresult(interop->GetInterface(IID_PPV_ARGS(&surface)));
// get surface dimensions
DXGI_SURFACE_DESC desc;
check_hresult(surface->GetDesc(&desc));
// create a CPU-readable texture
// note: for max perf, the texture creation
// should be done once per surface size
// or allocate a big enough texture (like adapter-sized) and copy portions
D3D11_TEXTURE2D_DESC texDesc{};
texDesc.Width = desc.Width;
texDesc.Height = desc.Height;
texDesc.ArraySize = 1;
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
texDesc.MipLevels = 1;
texDesc.SampleDesc.Count = 1;
texDesc.Usage = D3D11_USAGE_STAGING;
com_ptr<ID3D11Device> device;
check_hresult(surface->GetDevice(IID_PPV_ARGS(&device))); // or get the one from D3D11CreateDevice
com_ptr<ID3D11Texture2D> tex;
check_hresult(device->CreateTexture2D(&texDesc, nullptr, tex.put()));
com_ptr<ID3D11Resource> input;
check_hresult(interop->GetInterface(IID_PPV_ARGS(&input)));
com_ptr<ID3D11DeviceContext> dc;
device->GetImmediateContext(dc.put()); // or get the one from D3D11CreateDevice
// copy frame into CPU-readable resource
// this and the Map call can be done at each frame
dc->CopyResource(tex.get(), input.get());
D3D11_MAPPED_SUBRESOURCE map;
check_hresult(dc->Map(tex.get(), 0, D3D11_MAP_READ, 0, &map));
// TODO do something with map
dc->Unmap(tex.get(), 0);
}
}
}
}

Does 'this' pointer in bind C++ really matters?

I am trying to experiment bind in C++. Basically I have two class - Invokee. The invokee class registers a test handler that needs to be invoked upon some callbacks. The method here is -
void RegisterTestHandler(int id, TestFunction handler, std::string summary, std::string details);
Similarly, I have another method that actually invokes what has been registered -
void callHandler(int id);
Another class Test which has a function that needs to be invoked on callHandler.
unsigned int globalReset(int val);
In the main function, I am doing the nullptr for the second parameter in the bind. However, it still works and I don't get any crashes. Is it something working because of the compiler optimisation or undefined behaviour or it is something to do with bind concept.
Here is the entire experimental code.
// main.cpp
#include <iostream>
#include "test.h"
#include "invokee.h"
#include <memory>
#include <functional>
// beautify using clang-format in Vscode.
int main(int argc, char **argv)
{
auto *invokeTest = new Invokee();
Test *test = new Test();
std::string summary = "global reset summary";
std::string details = "global reset details";
//Basically there are two object from different class - InvokeTest --> does the registration of the handler.
// Now the InvokeTest has to call the member function of class object - Test.
// ?? How it can do - it can do using bind - basically, the this pointer of Test class is available to invokeTest
// therefore invokeTest can simply invoke the member function of test object.
// until the test point is valid, it can use it to invoke the method of it ?? --> Is it really correct?
delete(test); //experiment deleted the test pointer.
test= nullptr; // explicity set to nullptr
// still it works?? how come ??
invokeTest->RegisterTestHandler(1, std::bind(&Test::globalReset, test, std::placeholders::_1), summary, details);
invokeTest->callHandler(1);
return 0;
}
Here is the invokee.cpp -
#include "invokee.h"
void Invokee::RegisterTestHandler(int id, TestFunction handler, std::string summary, std::string details)
{
this->handlers[id] = handler;
this->summary[id] = summary;
this->details[id] = details;
}
void Invokee::callHandler(int id)
{
auto handler = handlers.find(id);
if (handler != handlers.end())
{
std::cout << "Found the handler --" << std::endl;
handler->second(1);
}
}
Here is the test.cpp
#include <iostream>
#include "test.h"
unsigned int Test::globalReset(int val)
{
std::cout << "global Reset invoked" << std::endl;
return 0;
}

How to use a Manager class to manage Characters and their animations in C++ using the SFML library

I'm trying to create a 2D sidescroller mini-game. For now, I only have a character with a sprite and one animation, which i'm trying to move using the left/right arrows. At first, I only had a Character class, storing the sprite of the character and its running animation. And it worked. But now, I'm trying to add a CharacterManager class, which will create all the characters to avoid doing it in the main, and which will manage their movements and draw them.
And it doesn't work anymore. I think my problems come from the fact that I have trouble using pointers, which I'm not really familiar with.
Here are the different classes I'm using :
Animation.h :
#pragma once
#include <vector>
#include <SFML/Graphics.hpp>
#include <stdexcept>
#include <ctime>
#include "Constants.h"
class Animation {
public:
Animation();
~Animation();
void SetFrames(std::vector<sf::IntRect> frames) { m_frames = frames; }
sf::IntRect Play();
private:
std::vector<sf::IntRect> m_frames;
unsigned int m_currentFrame;
float m_updateTime;
float m_timeSinceLastFrame;
float m_lastCallTimestamp;
float m_currentTimestamp;
bool m_firstCall;
};
Animation.cpp :
#include "Animation.h"
Animation::Animation() {
m_currentFrame = 0;
m_updateTime = 1.0f / ANIMATION_SPEED;
m_timeSinceLastFrame = 0.0f;
m_firstCall = true;
}
Animation::~Animation() {
}
sf::IntRect Animation::Play() {
if (m_frames.size() == 0) {
throw std::length_error("The frames vector is empty");
}
// Advance time and add the elapsed time to timeSinceLastFrame
m_currentTimestamp = std::clock();
// Ignore elapsed time if first call
if (m_firstCall) {
m_timeSinceLastFrame = 0.0f;
m_lastCallTimestamp = m_currentTimestamp;
m_firstCall = false; // Not first call anymore
}
else {
m_timeSinceLastFrame += (m_currentTimestamp - m_lastCallTimestamp) / CLOCKS_PER_SEC;
m_lastCallTimestamp = m_currentTimestamp;
}
// Next frame
if (m_timeSinceLastFrame >= m_updateTime) {
m_currentFrame++;
m_timeSinceLastFrame = 0;
// Check animation end
if (m_currentFrame >= m_frames.size()) {
m_currentFrame = 0; // Reset frame progression
m_firstCall = true; // Next passage will be the first call of a new animation
/* TODO : return something to alert the end of the animation
(like a specific rectint or set a variable to true and get it on the other side) */
}
}
return m_frames[m_currentFrame];
}
Character.h :
#pragma once
#include<string>
#include<iostream>
#include <SFML/Graphics.hpp>
#include <vector>
#include <map>
#include "Constants.h"
#include "Animation.h"
class Character : public sf::Drawable {
public:
Character();
Character(std::string name);
~Character();
void Move(float value);
// Setters
void SetTexture(std::string filename);
void SetPosition(sf::Vector2f pos) { m_position = pos; };
void SetAnimations(std::map<std::string, Animation*> animations) { m_animations = animations; };
protected:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
std::string m_name;
unsigned int m_orientation; // 0 (default) = right | 1 = left
std::map<std::string, Animation*> m_animations;
Animation runningAnimation;
sf::Vector2f m_position;
sf::Texture m_texture;
sf::Sprite m_sprite;
};
Character.cpp :
#include "Character.h"
Character::Character() {}
Character::Character(std::string name) {
m_name = name;
m_orientation = 0;
runningAnimation = Animation();
}
Character::~Character() {
}
void Character::draw(sf::RenderTarget& target, sf::RenderStates states) const {
target.draw(m_sprite, states);
}
void Character::Move(float value) {
m_sprite.setTextureRect(runningAnimation.Play());
m_position.x += value;
m_sprite.setPosition(m_position);
}
void Character::SetTexture(std::string filename) {
filename = TEXTURE_FILES_PREFIX + filename;
// Load the entire texture file
if (!m_texture.loadFromFile(filename))
std::cout << "Error loading texture file : " << filename << std::endl;
// Set the texture (by default, initialize to idle state) and the position
std::vector<sf::IntRect> runningFrames{
sf::IntRect(67, 45, 19, 28),
sf::IntRect(116, 46, 20, 27),
sf::IntRect(166, 48, 20, 25),
sf::IntRect(217, 45, 22, 28),
sf::IntRect(266, 46, 19, 27),
sf::IntRect(316, 48, 20, 25)
};
runningAnimation.SetFrames(runningFrames);
m_sprite.setTexture(m_texture);
m_sprite.setTextureRect(runningAnimation.Play());
m_sprite.setPosition(m_position);
}
CharacterManager.h :
#pragma once
#include <vector>
#include <map>
#include <iostream>
#include <SFML\Graphics.hpp>
#include "AliveCharacter.h"
#include "Npc.h"
#include "Animation.h"
#include "CharacterStats.h"
enum CharacterType
{
NPC,
ALIVE,
GENERAL
};
// Class containing a vector of character entities and creates the animations of these entities from a data file (later)
class CharacterManager : public sf::Drawable {
public :
CharacterManager();
~CharacterManager();
// Loads the file and stores the content inside data string (not used for now)
void LoadDataFile(std::string filename);
// Create a character and add it to the list
void CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos);
void CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos, std::map<std::string, Animation*> animations);
void CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos, std::map<std::string, Animation*> animations, CharacterStats stats);
void Move(float value);
Character* GetCharacter(std::string name) { return m_characters[name]; }
private :
// Calls the draw() function of each stored Character
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
std::string m_data;
std::map<std::string, Character*> m_characters;
};
CharacterManager.cpp :
#include "CharacterManager.h"
CharacterManager::CharacterManager() {
m_characters = std::map<std::string, Character*>();
}
CharacterManager::~CharacterManager() {
//delete m_characters;
}
void CharacterManager::LoadDataFile(std::string filename) {
// TODO : load file content
}
void CharacterManager::CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos) {
Character new_character(name); // Create a generic character...
// ... and specialise it depending on the character type param
switch (characterType)
{
case NPC:
new_character = Npc(name);
break;
case ALIVE:
new_character = AliveCharacter(name);
break;
default:
new_character = Character(name);
break;
}
// Set texture, position and add to the characters list
new_character.SetTexture(textureFilename);
new_character.SetPosition(pos);
m_characters.insert({ name, &new_character });
}
void CharacterManager::CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos, std::map<std::string, Animation*> animations) {
CreateCharacter(textureFilename, name, characterType, pos);
m_characters[name]->SetAnimations(animations);
}
void CharacterManager::CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos, std::map<std::string, Animation*> animations, CharacterStats stats) {
CreateCharacter(textureFilename, name, characterType, pos);
m_characters[name]->SetAnimations(animations);
//m_characters[name]->SetStats(stats);
}
void CharacterManager::Move(float value) {
for each (std::pair<std::string, Character*> pair in m_characters) {
Character* character = pair.second;
character->Move(value);
}
}
void CharacterManager::draw(sf::RenderTarget& target, sf::RenderStates states) const {
for each (std::pair<std::string, Character*> pair in m_characters) {
Character* character = pair.second;
target.draw(*character);
}
}
And finally the Main.cpp, where you can see in comments the things I tried without success :
#include "Map.h"
#include "CharacterManager.h"
int main()
{
sf::RenderWindow window(sf::VideoMode(WINDOW_SIZE_X, WINDOW_SIZE_Y), WINDOW_TITLE);
window.setFramerateLimit(WINDOW_FRAMERATE);
Map map;
int pos = WINDOW_SIZE_X / 2 - MAP_SIZE_X / 2;
float movement = 0;
map.SetPosition(pos);
map.SetGroundTexture("Foreground/Tileset.png");
map.SetBackgroundTexture("Background/BGFront.png");
CharacterManager charManager;
charManager.CreateCharacter("main", "Characters/test-character.png", ALIVE, sf::Vector2f(400, WINDOW_SIZE_Y - HEIGHT_OF_GROUND - 28));
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Left)
movement = -MOVING_SPEED;
else if (event.key.code == sf::Keyboard::Right)
movement = MOVING_SPEED;
}
else if (event.type == sf::Event::KeyReleased)
movement = 0;
}
// Move the map
map.Scroll(movement);
//charManager.GetCharacter("main")->Move(movement);
charManager.Move(movement);
window.clear();
window.draw(map);
/*Character* mainPerso = charManager.GetCharacter("main");
window.draw(*mainPerso);*/
window.draw(charManager);
window.display();
}
return 0;
}
The error I'm getting is on the return m_frames[m_currentFrame] line in Animation.cpp, in the end of the Play() function. A pop-up window opens saying : "Expression: vector subscript out of range". This error only happens the second time the code goes through this line. The first time it's called from the SetTexture() function of Character.cpp (m_sprite.setTextureRect(runningAnimation.Play())), itself called from the CreateCharacter() function of the CharacterManager (new_character.SetTexture(textureFilename)), and at this point the Animation object looks as it should.
But the second time, it's called from the Move() function of Character (m_sprite.setTextureRect(runningAnimation.Play())), itself called from the Move() function of the CharacterManager (character->Move(value)). And at this point, all of the Animation object absolutely doesn't look like it should. In debug mode, I can see this :
Debug screenshot
As I said earlier, I think the problem comes from the use of pointers. When I'm trying to remove them, the code runs, but I get a white square problem.
I tried to find some sort of tutorial on how to use this kind of architecture, but didn't find anything relevant. If you know one, I'll be glad to look at it.
As I said earlier, I think the problem comes from the use of pointers.
When I'm trying to remove them, the code runs, but I get a white
square problem.
yep, it is a common issue for SFML when using Texture and Sprite when shallow copy is used.
Let's look at sf::Sprite::setTexture reference:
The texture argument refers to a texture that must exist as long as
the sprite uses it. Indeed, the sprite doesn't store its own copy of
the texture, but rather keeps a pointer to the one that you passed to
this function. If the source texture is destroyed and the sprite tries
to use it, the behavior is undefined.
So, a class like below, with default generated copy operation by compiler:
class Foo {
public:
void setT() {
// generate texture {t}
s.setTexture(t);
}
sf::Sprite s;
sf::Texture t;
};
will bring troubles to you. Because when a copy is made by Foo f(otherFoo);, sprite in newly created instance of Foo will have pointer to texture of otherFoo - it is shallow copy of pointer to sf::Texture. Deleting otherFoo will make a dangle pointer inside new constructed object.
In this case, you should implement assignment operation which makes deep copy of texture for sprite. If you don't know how to do it, you should mark assignment operations as deleted:
class Character : public sf::Drawable {
public:
Character();
Character(std::string name);
~Character();
// added
Character& operator=(const Character&) = delete;
Character(const Character&) = delete;
void Move(float value);
Then, compiler will give you an error for each attempt of copying of Character instance.
In case of deleted copy operation, you should rely on pointers. Your attempt failed, because you store pointer to local variables. Local variables are deleted at the end of a function scope, and referring to them later is undefined behaviour.
You have to create Character by operator new:
void CharacterManager::CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos) {
Character* new_character = new Character(name); // Create a generic character...
//...
// Set texture, position and add to the characters list
new_character->SetTexture(textureFilename);
new_character->SetPosition(pos);
m_characters.insert({ name, new_character });
}

Show grey level value of pixel in Qt when the mouse is over it

Currently I am working on the display of gray level image with zoom feature. I am able to get the position of the pixel and the zoom feature is working well. However I encountered two problems:
1.) How can I get the grey level value of the pixel that is pointed by the mouse? I only managed to obtain the rgb value through “QRgb rgbValue = pix.toImage().pixel(x,y)”. How can I convert it into grey level value? Or is there any direct way to get the grey level value of the pixel.
2.) I have implemented “mouseMoveEvent(QMouseEvent *event)” and “setMouseTracking(true)”. However the function of “mouseMoveEvent(QMouseEvent *event)” is not functioning when I move the mouse. What is wrong with my code?
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsItem>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
protected:
void mouseMoveEvent(QMouseEvent * event);
private:
Ui::MainWindow *ui;
QGraphicsScene* scene;
QGraphicsItem* item;
QPixmap pix;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QImage image("E:/image_00002.bmp");
pix = QPixmap::fromImage(image);
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
scene->addPixmap(pix);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
ui->graphicsView->setMouseTracking(true);
}
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
QPoint local_pt = ui->graphicsView->mapFromGlobal(event->globalPos());
QPointF img_coord_pt = ui->graphicsView->mapToScene(local_pt);
double x = img_coord_pt.x();
double y = img_coord_pt.y();
/* How can I get a gray level image here */
QRgb rgbValue = pix.toImage().pixel(x,y);
ui->label_X->setText(QString::number(x));
ui->label_Y->setText(QString::number(y));
ui->label_Value->setText(QString::number(rgbValue));
}
To elaborate a bit on what hank said. In order for your QMainWindow to receive the events from the QGraphicsScene you need to install an event filter (see http://qt-project.org/doc/qt-4.8/qobject.html#installEventFilter ). Quoting from the DOCs:
An event filter is an object that receives all events that are sent to this object.
The filter can either stop the event or forward it to this object.
In order to process the events you need to define an eventFilter method in your main window class. Below are the on_pushButton_clicked() and eventFilter() methods that should do what you want:
void MainWindow::on_pushButton_clicked()
{
ui->graphicsView->setMouseTracking(true);
scene->installEventFilter(this);
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::GraphicsSceneMouseMove ) {
QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
QPointF img_coord_pt = mouseEvent->scenePos();
double x = img_coord_pt.x();
double y = img_coord_pt.y();
QColor color = QColor(pix.toImage().pixel(x,y));
int average = (color.red()+color.green()+color.blue())/3;
ui->label_X->setText(QString::number(x));
ui->label_Y->setText(QString::number(y));
ui->label_Value->setText(QString::number(average));
return true;
} else {
return QObject::eventFilter(obj, event);
}
}
Does this help?

Owner draw CSliderCtrl using MFC: why my program-created slider has an incorrect channel rect?

I am trying to implement an owner draw CSliderCtrl. It seems drawing is fine, however the mouse to change the thumb position is very weird. It is limited only in a very small rect. And I found that the rect by GetChannelRect is much smaller than the rect I used to create the slider control.
Below is .h file:
#if !defined(AFX_OWNDRAWSLIDER_H__82981708_4CBC_4D1E_8982_504E99BE489D__INCLUDED_)
#define AFX_OWNDRAWSLIDER_H__82981708_4CBC_4D1E_8982_504E99BE489D__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// OwnDrawSlider.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// COwnDrawSlider window
class COwnDrawSlider : public CSliderCtrl
{
// Construction
public:
COwnDrawSlider();
// Attributes
public:
CBrush black_brush;
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(COwnDrawSlider)
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~COwnDrawSlider();
// Generated message map functions
protected:
//{{AFX_MSG(COwnDrawSlider)
afx_msg void OnPaint();
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_OWNDRAWSLIDER_H__82981708_4CBC_4D1E_8982_504E99BE489D__INCLUDED_)
Here is the OwnDrawSlider class cpp:
// OwnDrawSlider.cpp : implementation file
//
#include "stdafx.h"
#include "OwnDrawSlider.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// COwnDrawSlider
COwnDrawSlider::COwnDrawSlider()
{
black_brush.CreateSolidBrush(RGB(0,0,0));
}
COwnDrawSlider::~COwnDrawSlider()
{
}
BEGIN_MESSAGE_MAP(COwnDrawSlider, CSliderCtrl)
//{{AFX_MSG_MAP(COwnDrawSlider)
ON_WM_PAINT()
ON_WM_CTLCOLOR()
ON_WM_ERASEBKGND()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// COwnDrawSlider message handlers
void COwnDrawSlider::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
CRect channelRect,thumbRect;
GetChannelRect(&channelRect);
GetThumbRect(&thumbRect);
GetClientRect(&channelRect);
thumbRect=channelRect;
channelRect.top+=5;
channelRect.bottom-=5;
int mid=(channelRect.top+channelRect.bottom)/2;
int w=channelRect.right-channelRect.left;
int pos=GetPos();
int minVal,maxVal;
GetRange(minVal,maxVal);
thumbRect.left=(pos-minVal)*w/(maxVal-minVal);
thumbRect.right=thumbRect.left+(channelRect.right-channelRect.left)*0.025f;
thumbRect.top+=12;
thumbRect.bottom-=12;
//draw the channel
//CBrush whiteBrush(RGB(255,255,255));
//dc.SelectObject(whiteBrush);
//dc.FrameRect(&channelRect,&whiteBrush);
//draw the thumb
CBrush yellowBrush(RGB(255,255,0));
dc.SelectObject(yellowBrush);
dc.Ellipse(&thumbRect);
CFont myFont;
myFont.CreatePointFont(96,"Tahoma");
dc.SetBkColor(RGB(0,0,0));
dc.SetTextColor(RGB(255,255,255));
dc.SelectObject(&myFont);
char msg[128];
sprintf(msg,"%d",pos);
CRect msgRect=thumbRect;
msgRect.top=thumbRect.bottom;
msgRect.bottom=msgRect.top+16;
int mid0=(thumbRect.left+thumbRect.right)/2;
msgRect.left=mid0-6*strlen(msg);
msgRect.right=mid0+6*strlen(msg);
dc.DrawText(msg,strlen(msg),&msgRect,DT_CENTER);
sprintf(msg,"%d",minVal);
msgRect.left=channelRect.left;
msgRect.right=channelRect.left+12*strlen(msg);
dc.DrawText(msg,strlen(msg),&msgRect,DT_LEFT);
sprintf(msg,"%d",maxVal);
msgRect.left=channelRect.right-12*strlen(msg);
msgRect.right=channelRect.right;
dc.DrawText(msg,strlen(msg),&msgRect,DT_RIGHT);
//draw the axis
CPen yellowPen(PS_SOLID,3,RGB(255,255,255));
dc.SelectObject(yellowPen);
dc.MoveTo(channelRect.left,mid);
dc.LineTo(channelRect.right,mid);
dc.MoveTo(channelRect.left,channelRect.top+12);
dc.LineTo(channelRect.left,channelRect.bottom-12);
dc.MoveTo(channelRect.right,channelRect.top+12);
dc.LineTo(channelRect.right,channelRect.bottom-12);
CPen thinPen(PS_SOLID,1,RGB(255,255,0));
dc.SelectObject(thinPen);
int numTick=GetNumTics();
DWORD* ptick=GetTicArray();
float pixelPerTick=w*1.0/numTick;
for(int i=0;i<numTick;i++)
{
dc.MoveTo((ptick[i])*pixelPerTick+channelRect.left,mid-3);
dc.LineTo((ptick[i])*pixelPerTick+channelRect.left,mid+3);
}
// Do not call CSliderCtrl::OnPaint() for painting messages
}
HBRUSH COwnDrawSlider::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CSliderCtrl::OnCtlColor(pDC, pWnd, nCtlColor);
// TODO: Change any attributes of the DC here
// TODO: Return a different brush if the default is not desired
return black_brush;
}
BOOL COwnDrawSlider::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
RECT client;
GetClientRect(&client);
//COLORREF color=pDC->GetBkColor();
COLORREF color=::GetSysColor(COLOR_WINDOW);
//FillRect(pDC->m_hDC,&client,::GetStockObject(GRAY_BRUSH));
//pDC->FillSolidRect(&client,color);
pDC->FillSolidRect(&client,RGB(0,0,0));
return true;//do not call OnEraseBkgrnd, it will fill it white
//return CSliderCtrl::OnEraseBkgnd(pDC);
}
Create the slider using program (no resource associated with it):
pFrameSlider=new COwnDrawSlider();
pFrameSlider->Create(WS_CHILD|WS_VISIBLE|BS_OWNERDRAW|TBS_HORZ|TBS_AUTOTICKS,rButton,this,ID_FRAME_SLIDER);
//pFrameSlider->SizeToContent();
pFrameSlider->SetTicFreq(50);
pFrameSlider->ShowWindow(SW_SHOW);
In the parent window, the NM_RELEASECAPTURE is trapped. When created, the rect=[9,57,384,822]. The rect obtained by the GetChannelRect is [19,23, 8, 40]. and the mouse operation is limited in this rect.
My question is: why the two rect are so different? How can I change the channel rect by program (without any resource associated with it)?

Resources