PlayerDropItemEvent does wrong things - bukkit

Today I wanted to cancel the PlayerDropItemEvent but if I go into my Inventory and do 'Option + Q' the itemstack dissapears
Src Code:
#EventHandler
public void onDrop(PlayerDropItemEvent event) {
event.setCancelled(true);
}
but if I do it like that the above mentioned problem happens.
The console doesn't show something either

If you cancel an inventory-bound event, it could be possible that the player's inventory doesn't get updated. Use
new BukkitRunnable() {
#Override
public void run() {
p.updateInventory();
}
}.runTask(plugin);
(delay because you can't do 2 inventory bound actions in 1 tick).
PS: Get an instance of your plugin by using MyMain.getPlugin(MyMain.class).

Related

How to not break bindings in qml?

I currently have an image which becomes visible or not depending on some steps of a process. The qml code for that image is the following :
Image
{
id : cameraDisplay
visible : mainViewModel.getCurrentSegmentIsCameraDisplayed
anchors.centerIn : parent
source: "Images/Todo.png"
}
I also have a button, which the user can press to display that image or not :
Button
{
Layout.fillWidth: true
Layout.fillHeight: true
buttonText : "CAMERA"
onClicked: {cameraDisplay.visible = !cameraDisplay.visible;}
}
In the c++, the binding looks like this :
Q_PROPERTY(bool getCurrentSegmentIsCameraDisplayed
READ getCurrentSegmentIsCameraDisplayed
NOTIFY segmentChanged)
the idea is that every time the current step of the process changes in my program, a notification is sent. That notification is then sent to the QML, which then gets the backend value to know if the camera should display or not that image.
I also have a button, which allows the user to toggle on or off the visibility of that image. The problem is that once that button is clicked, I lose the Q_PROPERTY binding, which means that once I go to the next segment, the notifications sent to the qml won't change the visibility of the image.
So basically, what I would want would be the following situation :
The segment changes, a notification is sent to the qml, and the visiblity of the image is updated automatically.
The user presses the button, which toggles the visibility of that image.
The segment changes again, a notification is sent to the qml, and the visibility of that image is again updated according to the backend.
Currently, step 3 doesn't work. What should I change to make it work?
thanks
You can change your binding in C++ to emit a signal when a change occurs, like this:
Q_PROPERTY(bool getCurrentSegmentIsCameraDisplayed
READ getCurrentSegmentIsCameraDisplayed
WRITE setCurrentSegment
NOTIFY segmentChanged)
In your class.h,
class MyClass : public QObject
{
Q_OBJECT
bool _segment;
public:
const bool &getCurrentSegmentIsCameraDisplayed() const;
public slots:
void setCurrentSegment(const bool &newSegment);
signals:
void segmentChanged(const bool &segment);
};
In your class.cpp,
void MyClass::setCurrentSegment(const bool &newSegment)
{
if (_segment == newSegment){
return;
}else{
_segment = newSegment;
emit segmentChanged(_segment);
}
}
const bool &MyClass::getCurrentSegmentIsCameraDisplayed() const
{
return _segment;
}
Now in C++ you can change the process value any way you want. On the QML side, when you need to change the property, just use the SLOT setCurrentSegment passing its new state:
Image
{
id : cameraDisplay
visible: mainViewModel.getCurrentSegmentIsCameraDisplayed
anchors.centerIn : parent
source: "https://www.cleverfiles.com/howto/wp-content/uploads/2018/03/minion.jpg"
}
Button
{
text : "CAMERA"
onClicked: {
mainViewModel.setCurrentSegment(!cameraDisplay.visible)
}
}
The binding is maintained regardless of where the change takes place.
I think you don't want your Button to directly change the visibility. You want it to change some other flag that the visibility depends on. How about something like this:
property bool showImage: true
Image
{
id : cameraDisplay
visible : showImage && mainViewModel.getCurrentSegmentIsCameraDisplayed
}
Button
{
onClicked: {showImage = !showImage}
}

Updating QChart from QLineSeries in a running while loop

I want to make my QChart dynamically update whenever a point is added to the QLineSeries object attached to it, but it seems that this update only occurs after the while loop I am running has finished. I am using said while loop in interface.cpp that calls a function updatePlot() which adds the data point to the line series, but this only updates the chart after the while loop has completely finished. Pseudo code of what is happening here:
qtwindow.cpp
// Constructor that initializes the series which will be passed into the interface
AlgoWindow::AlgoWindow( ..., TradingInterface* interface, ... ) {
...
QLineSeries* series = new QLineSeries();
QLineSeries* benchmark = new QLineSeries();
QChart* chart = new QChart();
chart->addSeries(series);
chart->addSeries(benchmark);
// Also creates custom axes which are attached to each series
...
}
// Slot connected to a button signal
void AlgoWindow::buttonClicked() {
// Runs the backtest
interface->runbacktest(..., series, benchmark, ...);
}
interface.cpp
void TradingInterface::runbacktest(..., QtCharts::QLineSeries* algoplot, QtCharts::QLineSeries* benchplot) {
// Runs a huge while loop that continuously checks for events
while (continue_backtest) {
if (!eventsqueue.isEmpty()) {
// Handle each event for the bar
} else {
// All events have been handled for the day, so plot
updatePlot(algoplot, benchplot);
}
}
}
void TradingInterface::updatePlot(QtCharts::QLineSeries *algoseries,
QtCharts::QLineSeries *benchseries) {
// Get the date and the information to put in each point
long date = portfolio.bars->latestDates.back();
double equitycurve = portfolio.all_holdings.rbegin().operator*().second["equitycurve"];
double benchcurve = benchmarkportfolio.all_holdings.rbegin().operator*.second["equitycurve"];
// Append the new points to their respective QLineSeries
algoseries->append(date * 1000, equitycurve*100);
benchseries->append(date * 1000, benchcurve*100);
}
This gives me no errors and the while loop completes, but the lines are only plotted after runbacktest() exits. It then plots all the data correctly, but all at once.
What I need to happen is for the QChart to update every time the lines are added, which my guess was to use some form of custom signal-slot listener but I have no clue how to go about that. If the graph will not update until after the function completes, is it even possible within the QChart framework?
Also, I have already tried QChart::update() and QChartView::repaint(). Both produced the same results as without.
EDIT: I tried setting up a new thread that emits a signal back to the main thread whenever the data is completed but it seems to have changed nothing. The QChart still does not update until after all the data has been inputted. I added a couple lines to help debug and it seems like the function which emits the signal runs consistently just fine, but the slot function which receives the signal only runs after the thread has finished. Not only that, but slowing the signals down with a sleep does not make it plot slowly (like I thought), as the QChart still refuses to update until after the final update to addData().
Either remove your while loop and perform the work one step at a time with a timer.
Or run your runbacktest function in another thread and send a signal to update the QChart in the UI's thread when the data is ready.
Either way you need to give control back to the event loop so that the chart can be repainted.
The Qt idiom for running an operation “continuously” is to use a zero-duration “timer”. It’s not a timer really, but Qt calls it one.
You can do the operation in chunks that take approximately a millisecond. For this, invert the control flow. Qt doesn't provide too much syntactic sugar for it, but it's easy to remedy.
Convert this code, which maintains a loop:
for (int i = 0; i < 1000; ++i) {
doSomething(i);
}
into this lambda, which is invoked by the event loop:
m_tasks.addTask([this](i = 0) mutable {
doSomething(i);
++i;
return i < 1000;
});
assuming:
class Controller : public QObject {
Tasks m_tasks;
...
};
where the Tasks class maintains a list of tasks to be executed by the event loop:
class Tasks : public QObject {
Q_OBJECT
QBasicTimer timer;
std::list<std::function<bool()>> tasks;
protected:
void timerEvent(QTimerEvent *ev) override {
if (ev->timerId() != timer.timerId())
return;
for (auto it = tasks.begin(); it != tasks.end(); ) {
bool keep = (*it)();
if (!keep)
it = tasks.erase(it);
else
++it;
}
if (tasks.empty())
timer.stop();
}
public:
using QObject :: QObject;
template <typename F> void addTask(F &&fun) {
tasks.emplace_back(std::forward(fun));
if (!timer.isActive())
timer.start(0, this);
}
};

GLFW Keyboard Input Registers As Multiple Clicks

In my current LWJGL application I am using the GLFW window input handler which I have set up a class to handle called Keyboard.java which extends GLFWKeyCallback. I have correctly set up my keyboard input class but when I click on a key if i do not click if fast enough (very quickly) then it registers as multiple clicks. I have presented some documentation below:
Keyboard Class
public class Keyboard extends GLFWKeyCallback {
//Variables
public static boolean keys[] = new boolean[65536];
#Override
public void invoke(long window, int key, int scancode, int action, int mods) {
keys[key] = action == GLFW_PRESS;
}
}
Implementation
public static void handleInput() {
if (Keyboard.keys[GLFW_KEY_SPACE]) {
System.out.println("Space");
glfwPollEvents();
}
}
The above method is implemented in the main game loop and is called once a frame.
Result
Initialised LWJGL Version: 3.1.2 build 29
Space
Space
Space
Space
The above: "Space" should be outputted every time that I click space but when I click it relatively fast, Then i get the above result of many "spaces".
Conclusion: Is it possible for a click of space to be registered only once no matter how long you hold it. Thanks
In your handleInput() function, you are testing to see if Keyboard.keys[GLFW_KEY_SPACE] is true, and if it is, you execute the statement. The problem is that this test only becomes false when you stop hitting space, which could take seconds to happen.
My suggestion: once you tested for Keyboard.keys[GLFW_KEY_SPACE], make it false.
public static void handleInput() {
if (Keyboard.keys[GLFW_KEY_SPACE]) {
Keyboard.keys[GLFW_KEY_SPACE] = false;
System.out.println("Space");
glfwPollEvents();
}
}

Hiding / showing markers: OSMDroid / OpenMaps

I have an app which uses or googlemaps or openMaps (offline) depending of connection state.
In each case there are markers, for places or point of interest or… I want that the user can display or hide some category of markers.
When using google maps I have a menu and in the action bar when some item is selected it toggles between showing or hiding the markers from the correpondent category; As for google maps that works easily & perfectly using isVisible();
As for osmdroid i have not found in the doc any equivalent to isVisible(), neither any show() or hide() method. So I have tried to use as a workaround somemarkers.getAlpha() & somemarkers.setAlpha(), toggling between 0 & 1 alpha values.
No error occurs but the visibility of markers remains the same, not toggling, or only randomly when i tap 10 or 20 times on the action icon.
In the log i get "InputEventReceiver: Attempted to finish an input event but the input event receiver has already been disposed" which seems to me to be the cause.
But what to do to avoid this?
KitKat, SonyXperia Z
In osmdroid, the method to hide/show overlays (markers) is:
Overlay.setEnabled(boolean enabled)
I have done this bit differently.
Extend ItemizedIconOverlay
Add as an overlay to mapView
Hide markers by using removeAllItems or removeItem
Show marker by adding it to the itemized overlay list
Create a new Overlay class by extending ItemizedIconOverlay.
Note: WaypointOverlayItem extends OverlayItem. {It's your custom overlay model class}
public class NavigatorItemizedOverlay extends ItemizedIconOverlay<WaypointOverlayItem> {
private Context mContext;
public NavigatorItemizedOverlay(final Context context, final List<WaypointOverlayItem> aList) {
super(context, aList, new OnItemGestureListener<WaypointOverlayItem>() {
#Override
public boolean onItemSingleTapUp(int index, WaypointOverlayItem item) {
return false;
}
#Override
public boolean onItemLongPress(int index, WaypointOverlayItem item) {
return false;
}
});
// TODO Auto-generated constructor stub
mContext = context;
}
}
Add this Overlay to your map
//Add Itemized overlay
navigatorItemizedOverlay = new NavigatorItemizedOverlay(getActivity(), waypointOverlayItemList);
mapView.getOverlays().add(navigatorItemizedOverlay);
To Add marker:
navigatorItemizedOverlay.addItem(waypointOverlayItem);
To hide all markers:
navigatorItemizedOverlay.removeAllItems();
There are other methods:
removeItem(position) and removeItem(waypointOverlayItem)

LWUIT List works terribly slow

I've faced with the well-known problem in LWUIT. My list component with the checkbox renderer scrolls very slow. If to test my application on emulator it runs quite smoothly (nevertheless I see CPU utilization splashes up to 60% during scroll action), but if to run it on mobile phone it takes a couple of seconds between focus movements.
There's a code of renderer:
public class CheckBoxMultiselectRenderer extends CheckBox implements ListCellRenderer {
public CheckBoxMultiselectRenderer() {
super("");
}
//override
public void repaint() {
}
public Component getListCellRendererComponent(List list, Object value,
int index,boolean isSelected) {
Location loc = (Location)value;
setText(loc.getLocationName());
setFocus(isSelected);
setSelected(loc.isSelected());
return this;
}
public Component getListFocusComponent(List list) {
setText("");
setFocus(true);
getStyle().setBgTransparency(Consts.BG_TRANSPARENCY);
return this;
}
}
that's the code of my form containing the list:
protected void createMarkup() {
Form form = getForm();
form.setLayout(new BorderLayout());
form.setScrollable(false);
Label title = new Label("Choose location zone:");
title.getStyle().setMargin(5, 5, 0, 0);
title.getStyle().setBgTransparency(Consts.BG_TRANSPARENCY);
title.setAlignment(Component.CENTER);
form.addComponent(BorderLayout.NORTH, title);
list = new List(StateKeeper.getLocationsAsList());
list.setFixedSelection(List.FIXED_NONE_CYCLIC);
// list.setSmoothScrolling(true);
list.getStyle().setBgTransparency(0);
list.setListCellRenderer(new CheckBoxMultiselectRenderer());
list.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
// List l = (List)ae.getSource();
// l.requestFocus();
// l.setHandlesInput(true);
Location selItem = (Location)list.getSelectedItem();
selItem.setSelected(!selItem.isSelected());
}
});
form.addComponent(BorderLayout.CENTER, list);
}
I would be very thankful for any help!
We must be so carefull building lwuit List. If we have made something wrong they can work worse than expected. I recommend you to take a look on this
LWUIT Blog ListRender
You can also rewrite your paint method. You list's speed will be increased.