Irrlicht : can't call onEvent - irrlicht

i'm new with irrlicht and i was trying to implement key events. I followed the irrlicht tutoriel on their website but it doesn't work.
Here's the code :
class MyEventReceiver : public irr::IEventReceiver
{
public:
MyEventReceiver()
{
for (irr::u32 i = 0; i < irr::KEY_KEY_CODES_COUNT; ++i)
KeyIsDown[i] = false;
}
virtual bool OnEvent(const irr::SEvent& event)
{
std::cout << event.EventType << std::endl;
if (event.EventType == irr::EET_KEY_INPUT_EVENT)
KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
return (false);
}
virtual bool IsKeyDown(irr::EKEY_CODE keyCode) const
{
return (KeyIsDown[keyCode]);
}
private:
bool KeyIsDown[irr::KEY_KEY_CODES_COUNT];
};
Normally if i press a button the onEvent should be called but i can press any button i want it never calls this function. Of course i created a MyEventReceiver in the main.
Can someone who knows irrlicht help me please ?

I got the same problem, it's because you created it but you don't give it when you create your device: like this, IrrlichtDevice* device = createDevice(driverType,
core::dimension2d<u32>(640, 480), 16, false, false, false, --->&receiver<---);

Related

How to "refresh" TListBox?

I'm creating an app which shows bill numbers, like the one you see at Mcdonald's. A POS system send bill numbers to my app and the numbers are showed in a TListBox called "ListBoxPrep". Then, when the POS system sends my app the number of a bill to be removed, my app gets rid of it from "ListBoxPrep" and add it to "ListBoxReady". Every communication between the POS and my app is done via TCP connection and I have no problem with it.
The problem I'm facing is that I still see the number remain in "ListBoxPrep" even after deleting it by "pItem->Free();". "pItem" is a pointer of TListBoxItem. I want the numbers disappear as soon as my app receives the "delete signal" from the POS and especially without user's interation such as clicking the panel etc. I think of using TTimer, but I have no idea how to make "ListBoxPrep" refresh by itself. Do you have any idea to do that? Any suggestion would be appreciated. I'm using RAD Studio 10.4.
After my app received the "delete signal" from the POS, I still see the numbers at right side. They are supposed to disappear.
As soon as I click the "ListBoxPrep", the numbers disappear.
void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
{
//We receive data: POS --> Screen(PC)
String sentDataFromPOS = AContext->Connection->Socket->ReadLn();
if(sentDataFromPOS .IsEmpty())
{
ShowMessage("Data sent from POS is empty!");
return;
}
// 1. Find an order number to move to the right (prep -> ready)
int indexOrderToRemove = ListBoxPrep->Items->IndexOf(sentDataFromPOS);
// 2. Add the order number to the "Ready list"
addNumberToReady(sentDataFromPOS);
// 3. Remove the order from the "Prep list"
ListBoxPrep->BeginUpdate();
TListBoxItem* pItem = ListBoxPrep->ItemByIndex(indexOrderToRemove);
pItem->Free(); // HERE I have a problem
// test: To refresh the screen
LayoutLeft->Visible = false;
LayoutLeft->Visible = true;
/*
ListBoxPrep->Enabled = false;
ListBoxPrep->Visible = false;
ListBoxPrep->Enabled = true;
ListBoxPrep->Visible = true;
ListBoxPrep->Repaint();
*/
ListBoxPrep->EndUpdate();
}
TIdTCPServer is a multi-threaded component. Its OnExecute event is called in the context of a worker thread. As such, it MUST synchronize with the main UI thread when accessing UI controls (that goes for ShowMessage() too, BTW). You can use the RTL's TThread::Synchronize() (synchronous) or TThread::Queue() (asynchronous) method for that.
Also, you should not be Free()'ing the TListBoxItem objects directly. You have the index of the desired item, you can use ListBoxPrep->Items->Delete() instead.
If you are using one of the clang-based compilers, try something more like this:
void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
{
//We receive data: POS --> Screen(PC)
String sentDataFromPOS = AContext->Connection->Socket->ReadLn();
if (sentDataFromPOS.IsEmpty())
{
TThread::Synchronize(nullptr,
[](){ ShowMessage("Data sent from POS is empty!"); }
);
return;
}
TThread::Queue(nullptr, // or Synchronize(), your choice...
[=, this](){ this->orderIsReady(sentDataFromPOS); }
);
}
void __fastcall TForm1::orderIsReady(String orderNumber)
{
// 1. Find an order number to move to the right (prep -> ready)
int indexOrderToRemove = ListBoxPrep->Items->IndexOf(orderNumber);
// 2. Add the order number to the "Ready list"
addNumberToReady(orderNumber);
// 3. Remove the order from the "Prep list"
if (indexOrderToRemove != -1)
ListBoxPrep->Items->Delete(indexOrderToRemove);
}
If, on the other hand, you are using the "classic" Borland compiler, then try this instead:
struct orderHelper
{
String orderNumber;
orderHelper(const String &orderNumber)
: orderNumber(orderNumber)
{
}
void __fastcall orderIsReady()
{
Form1->orderIsReady(orderNumber);
}
};
void __fastcall TForm1::orderIsEmpty()
{
ShowMessage("Data sent from POS is empty!");
}
void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
{
//We receive data: POS --> Screen(PC)
String sentDataFromPOS = AContext->Connection->Socket->ReadLn();
if (sentDataFromPOS.IsEmpty())
{
TThread::Synchronize(NULL, &orderIsEmpty);
return;
}
orderHelper helper(sentDataFromPOS);
TThread::Synchronize(NULL, &(helper.orderIsReady));
}
void __fastcall TForm1::orderIsReady(String orderNumber)
{
// 1. Find an order number to move to the right (prep -> ready)
int indexOrderToRemove = ListBoxPrep->Items->IndexOf(orderNumber);
// 2. Add the order number to the "Ready list"
addNumberToReady(orderNumber);
// 3. Remove the order from the "Prep list"
if (indexOrderToRemove != -1)
ListBoxPrep->Items->Delete(indexOrderToRemove);
}
Or this:
struct orderHelper
{
String orderNumber;
orderHelper(const String &orderNumber)
: orderNumber(orderNumber)
{
}
void __fastcall orderIsReady()
{
try {
Form1->orderIsReady(orderNumber);
} __finally {
delete this;
}
}
};
void __fastcall TForm1::orderIsEmpty()
{
ShowMessage("Data sent from POS is empty!");
}
void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
{
//We receive data: POS --> Screen(PC)
String sentDataFromPOS = AContext->Connection->Socket->ReadLn();
if (sentDataFromPOS.IsEmpty())
{
TThread::Synchronize(NULL, &orderIsEmpty);
return;
}
orderHelper *helper = new orderHelper(sentDataFromPOS);
TThread::Queue(NULL, &(helper->orderIsReady));
}
void __fastcall TForm1::orderIsReady(String orderNumber)
{
// 1. Find an order number to move to the right (prep -> ready)
int indexOrderToRemove = ListBoxPrep->Items->IndexOf(orderNumber);
// 2. Add the order number to the "Ready list"
addNumberToReady(orderNumber);
// 3. Remove the order from the "Prep list"
if (indexOrderToRemove != -1)
ListBoxPrep->Items->Delete(indexOrderToRemove);
}
I modified some code in IdTCPServerExecute to remove a few compile errors. Here is the code which has worked well. Thank you again, Remy Lebeau !
void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
{
//We receive data: POS --> Screen(PC)
String sentDataFromPos = AContext->Connection->Socket->ReadLn();
// test
//sentDataFromPos = "";
if(sentDataFromPos.IsEmpty())
{
TThread::Synchronize(nullptr,
[=](){ ShowMessage("Data sent from POS is empty!"); }
);
return;
}
TThread::Synchronize(nullptr,
// Queue doesn't make the numbers disappear. It doesn't display them at right side either .
[&, this]()
{
this->orderIsReady(sentDataFromPos);
}
);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::orderIsReady(String orderNumber)
{
// 1. Find an order to move to the right (prep -> ready)
int indexOrderToRemove = ListBoxPrep->Items->IndexOf(orderNumber);
// 2. Add an order of the same order number to the "Ready list"
addNumberToReady(orderNumber);
// 3. Remove the order from the "Prep list"
if(indexOrderToRemove != -1)
{
ListBoxPrep->Items->Delete(indexOrderToRemove);
}
}

Aging values in a queue: Best use of Windows timers?

I have an std::set that contains unique values. I have an std::queue that holds the same values
in order to age the values in std::set.
I'd like to use a timer to determine when to pop a value from the queue and then erase the value from the set.
The timer is created/started every time data is added to an empty set/queue.
If data is added to a non-empty set/queue, no change is made to the timer.
The timer would fire every X milliseconds to execute a function.
The function would pop a value from the queue then erase that value from the set.
If the set/queue is now empty the timer would stop.
If the set/queue is not empty, no change is made to the timer.
This program runs in Windows 10.
Does this way make sense? Is there a better/more efficient/simpler way to age the data?
I've read the docs on Using Timer Queues so I see how the queue and the timers are created and destroyed. What I don't see is a recommendation for starting/stopping timers.
Should I be creating a new TimerQueueTimer to wait for X milliseconds once, run the func and then create a new TimerQueueTimer if the set/queue is not empty?
Should I instead create a single TimerQueueTimer to run periodically X milliseconds but delete it once the set/queue is empty?
Is there a 3rd technique I should use instead?
Here's my example code.
using unsignedIntSet = std::set<std::uint32_t>;
using unsignedIntQ = std::queue<std::uint32_t>;
unsignedIntQ agingQ;
unsignedIntSet agingSet;
HANDLE gDoneEvent = NULL;
HANDLE hTimer = NULL;
HANDLE hTimerQueue = NULL;
VOID CALLBACK ageTimer(PVOID lpParam, BOOLEAN TimerOrWaitFired)
{
if (!agingQ.empty())
{
auto c = agingQ.front();
agingSet.erase(c);
agingQ.pop();
if (!agingQ.empty())
{
// rerun CreateTimerQueueTimer() here?
}
}
SetEvent(gDoneEvent);
}
int createTimerForAgingQ()
{
// create timer if it doesn't already exist
if (gDoneEvent == NULL)
{
gDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (gDoneEvent == NULL)
{
std::cerr << "CreateEvent() error: " << WSAGetLastError() << std::endl;
return -1;
}
hTimerQueue = CreateTimerQueue();
if (hTimerQueue == NULL)
{
std::cerr << "CreateTimerQueue() error: " << WSAGetLastError() << std::endl;
return -1;
}
if (!CreateTimerQueueTimer(&hTimer, hTimerQueue, (WAITORTIMERCALLBACK)ageTimer, NULL, 500, 0, WT_EXECUTEONLYONCE))
{
std::cerr << "CreateTimerQueueTimer() error: " << WSAGetLastError() << std::endl;
return -1;
}
}
}
void addUnique(unsigned char* buffer, int bufferLen)
{
// hash value
auto h = hash(buffer, bufferLen);
// test insert into set
auto setResult = agingSet.emplace(h);
if (setResult.second)
{
// enqueue into historyQ
agingQ.emplace(h);
if (!gDoneEvent) createTimerForAgingQ();
}
}
Research shows that the CreateTimerQueue/CreateTimerQueueTimer may not be the way to go.
Use of ThreadpoolTimer

How can i use VALA delegates in GTK3 button callback?

I'm trying to understand Vala delegates with Gtk3.
I tested callback and lambda with no problem.
I wanna test a delegate callback, here my code :
using Gtk;
delegate void typeDelegate(Button button);
int main (string[] args) {
Gtk.init (ref args);
typeDelegate cb = cbLabelf;
var window = new Window ();
window.title = "First GTK+ Program";
window.border_width = 10;
window.window_position = WindowPosition.CENTER;
window.set_default_size (350, 70);
window.destroy.connect (Gtk.main_quit);
var button = new Button.with_label ("Click me!");
//button.clicked.connect (cb);
//button.clicked+= cb;
button.clicked.connect+=cb;
window.add (button);
window.show_all ();
Gtk.main ();
return 0;
}
void cbLabelf(Button button)
{
button.label = "tank yu";
}
I also red generated C code ( when i use lambda) to understand.
Here the compil error :
GTKsampleDelegate.vala:20.5-20.30: error: Arithmetic operation not supported for types Gtk.Button.clicked.connect' andtypeDelegate'
button.clicked.connect+=cb;
Well,
Seems that you want to get the intrinsic variable that holds the instance that emitted the signal, I find strange that vala doesn't let you use a delegate variable to obtain it via parameter, yet, you can use one of the forms below: using no delegation variable (A) or bypassing the error with a closure (B).
public class FooSignalClass : Object {
/* Gtk Button.clicked signal has the void f(void) signature */
public signal void on_foo ();
public void foo() {
on_foo();
}
}
public delegate void FooSignalFunc (FooSignalClass fooer);
void on_foo_handler (FooSignalClass fooer) {
long fooer_memory_address = (long)fooer;
GLib.message(#"fooer exists? $(fooer!=null).");
GLib.message(#"address=$fooer_memory_address.");
}
int main () {
var foo_signal = new FooSignalClass();
long fooer_memory_address = (long)foo_signal;
GLib.message(#"foo_signal address=$fooer_memory_address.");
/* Option A: Connect directly without the delegate variable */
foo_signal.on_foo.connect(on_foo_handler);
/* Option B: You cant use a delegate directly, bypass it with a closure */
FooSignalFunc func = on_foo_handler;
foo_signal.on_foo.connect((instance) => {
func(instance);
});
foo_signal.foo();
return 0;
}

alBufferData() sets AL_INVALID_OPERATION when using buffer ID obtained from alSourceUnqueueBuffers()

I am trying to stream audio data from disk using OpenAL's buffer queueing mechanism. I load and enqueue 4 buffers, start the source playing, and check in a regular intervals to refresh the queue. Everything looks like it's going splendidly, up until the first time I try to load data into a recycled buffer I got from alSourceUnqueueBuffers(). In this situation, alBufferData() always sets AL_INVALID_OPERATION, which according to the official v1.1 spec, it doesn't seem like it should be able to do.
I have searched extensively on Google and StackOverflow, and can't seem to find any reason why this would happen. The closest thing I found was someone with a possibly-related issue in an archived forum post, but details are few and responses are null. There was also this SO question with slightly different circumstances, but the only answer's suggestion does not help.
Possibly helpful: I know my context and device are configured correctly, because loading small wav files completely into a single buffer and playing them works fine. Through experimentation, I've also found that queueing 2 buffers, starting the source playing, and immediately loading and enqueueing the other two buffers throws no errors; it's only when I've unqueued a processed buffer that I run into trouble.
The relevant code:
static constexpr int MAX_BUFFER_COUNT = 4;
#define alCall(funcCall) {funcCall; SoundyOutport::CheckError(__FILE__, __LINE__, #funcCall) ? abort() : ((void)0); }
bool SoundyOutport::CheckError(const string &pFile, int pLine, const string &pfunc)
{
ALenum tErrCode = alGetError();
if(tErrCode != 0)
{
auto tMsg = alGetString(tErrCode);
Log::e(ro::TAG) << tMsg << " at " << pFile << "(" << pLine << "):\n"
<< "\tAL call " << pfunc << " failed." << end;
return true;
}
return false;
}
void SoundyOutport::EnqueueBuffer(const float* pData, int pFrames)
{
static int called = 0;
++called;
ALint tState;
alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
if(tState == AL_STATIC)
{
Stop();
// alCall(alSourcei(mSourceId, AL_BUFFER, NULL));
}
ALuint tBufId = AL_NONE;
int tQueuedBuffers = QueuedUpBuffers();
int tReady = ProcessedBuffers();
if(tQueuedBuffers < MAX_BUFFER_COUNT)
{
tBufId = mBufferIds[tQueuedBuffers];
}
else if(tReady > 0)
{
// the fifth time through, this code gets hit
alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));
// debug code: make sure these values go down by one
tQueuedBuffers = QueuedUpBuffers();
tReady = ProcessedBuffers();
}
else
{
return; // no update needed yet.
}
void* tConverted = convert(pData, pFrames);
// the fifth time through, we get AL_INVALID_OPERATION, and call abort()
alCall(alBufferData(tBufId, mFormat, tConverted, pFrames * mBitdepth/8, mSampleRate));
alCall(alSourceQueueBuffers(mSourceId, 1, &mBufferId));
if(mBitdepth == BITDEPTH_8)
{
delete (uint8_t*)tConverted;
}
else // if(mBitdepth == BITDEPTH_16)
{
delete (uint16_t*)tConverted;
}
}
void SoundyOutport::PlayBufferedStream()
{
if(!StreamingMode() || !QueuedUpBuffers())
{
Log::w(ro::TAG) << "Attempted to play an unbuffered stream" << end;
return;
}
alCall(alSourcei(mSourceId, AL_LOOPING, AL_FALSE)); // never loop streams
alCall(alSourcePlay(mSourceId));
}
int SoundyOutport::QueuedUpBuffers()
{
int tCount = 0;
alCall(alGetSourcei(mSourceId, AL_BUFFERS_QUEUED, &tCount));
return tCount;
}
int SoundyOutport::ProcessedBuffers()
{
int tCount = 0;
alCall(alGetSourcei(mSourceId, AL_BUFFERS_PROCESSED, &tCount));
return tCount;
}
void SoundyOutport::Stop()
{
if(Playing())
{
alCall(alSourceStop(mSourceId));
}
int tBuffers;
alCall(alGetSourcei(mSourceId, AL_BUFFERS_QUEUED, &tBuffers));
if(tBuffers)
{
ALuint tDummy[tBuffers];
alCall(alSourceUnqueueBuffers(mSourceId, tBuffers, tDummy));
}
alCall(alSourcei(mSourceId, AL_BUFFER, AL_NONE));
}
bool SoundyOutport::Playing()
{
ALint tPlaying;
alCall(alGetSourcei(mSourceId, AL_SOURCE_STATE, &tPlaying));
return tPlaying == AL_PLAYING;
}
bool SoundyOutport::StreamingMode()
{
ALint tState;
alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
return tState == AL_STREAMING;
}
bool SoundyOutport::StaticMode()
{
ALint tState;
alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
return tState == AL_STATIC;
}
And here's an annotated screen cap of what I see in my debugger when I hit the error:
I've tried a bunch of little tweaks and variations, and the result is always the same. I've wasted too many days trying to fix this. Please help :)
This error occurs when you trying to fill buffer with data, when the buffer is still queued to the source.
Also this code is wrong.
if(tQueuedBuffers < MAX_BUFFER_COUNT)
{
tBufId = mBufferIds[tQueuedBuffers];
}
else if(tReady > 0)
{
// the fifth time through, this code gets hit
alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));
// debug code: make sure these values go down by one
tQueuedBuffers = QueuedUpBuffers();
tReady = ProcessedBuffers();
}
else
{
return; // no update needed yet.
}
You can fill buffer with data only if it unqueued from source. But your first if block gets tBufId that queued to the source. Rewrite code like so
if(tReady > 0)
{
// the fifth time through, this code gets hit
alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));
// debug code: make sure these values go down by one
tQueuedBuffers = QueuedUpBuffers();
tReady = ProcessedBuffers();
}
else
{
return; // no update needed yet.
}

Qt4 drop (xml)files from win explorer rejected by TableModel

I got a project that required drag & drop xml files from windows explorer into a TableModel, whatever I tried, that widget rejects(with the annoying block icon) the process and not any functions below are called.
i've tried the following:
reimplement QAbstarctTableView::flags to support drag & drop
remiplement QAbstractTableView::supportedDropActions.
remiplement QAbstractTableView::mimeTypes. return "text/uri-list", "text/plain", "application/xml", "text/xml". (some said that "text/uri-list" shall be enough.)
according to most posts i found in the internet, I shall be able to drag files into the TableView Widget now. That's not true for me. T_T
here's my code.
// set the flags to accept drop & drag
Qt::ItemFlags XMLFileModel::flags(const QModelIndex& index) const {
Qt::ItemFlags defaultFlags = Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
if (index.isValid())
return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
else
return Qt::ItemIsDropEnabled | defaultFlags;
}
.
// drop mime data
bool XMLFileModel::dropMimeData(const QMimeData *data,
Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
qDebug() << "Drop Mime data" << endl;
if (action == Qt::IgnoreAction)
return true;
if (! data->hasUrls())
return false;
QList<QUrl> urls = data->urls();
foreach(QUrl url , urls) {
std::shared_ptr<QFile> file(new QFile(url.path()));
if (! file->open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox::warning(NULL, QString("note"), QString("unable to open file!"));
return false;
}
XMLFilePtr xml(new XMLFile(file->fileName(), file));
addXMLFile(xml);
}
return true;
}
.
Qt::DropActions XMLFileModel::supportedDropActions() const
{
qDebug () << "supportedDropActions";
return Qt::CopyAction | Qt::MoveAction;
}
.
// define the acceptable mime type
QStringList XMLFileModel::mimeTypes() const
{
qDebug () << "mimeTypes";
QStringList types;
types << "text/uri-list" << "text/plain" << "application/xml" << "text/xml";
qDebug() << types;
return types;
}
.
I tried to add
QMimeData* mimeData(const QModelIndexList &indexes) const;
and now I could drag&drop inside the tableview or even between table views. debug messages print as well.
then I continued to do the test.
I wrote a test class:
class test : public QTableView
{
Q_OBJECT
public:
explicit test(QWidget *parent = 0);
virtual void dropEvent(QDropEvent *event);
virtual void dragEnterEvent ( QDragEnterEvent * event );
void startDrag ( Qt::DropActions supportedActions );
};
.
void test::dropEvent(QDropEvent *event) {
qDebug() << "test";
qDebug() << event->mimeData()->formats();
event->accept();
}
void test::dragEnterEvent(QDragEnterEvent *event) {
qDebug() << "drag enter";
qDebug() << event->mimeData();
event->accept();
}
void test::startDrag(Qt::DropActions supportedActions) {
qDebug() << "true";
}
.
and add a new test widget in the mainWindow that accepts the same model.
It amazed me that drag&drop internally or between table views is still working. but when I tried to drop the item from my desktop, none of these three functions are called.
now I am thinking that the problem might be the incompatible mime-type between my OS and Qt D&D framework. I may not return the right mime type
any one suffered and solved this problem or any suggestions? >_<
= = = = = = = =
hey, I got the same problem with the drop site example, too!
I don't think you need to reimplement any of those functions except for dragEnterEvent and dropEvent. Did you call QWidget::setAcceptDrops(true)? This is important.

Resources