Related
I'm trying to get the behavior that when I drag and drop a MyButton, the dropEvent will be triggered in any part of the interface. Right now it works pretty much as needed, except for one thing. The dropEvent doesn't work if the mouse button is released between widgets, and I don't know how to fix this problem. For me it is very important that the dropEvent is always triggered, at the moment when the drag is finished, because at that moment I send a message to the server about the move made, and if at that moment the mouse was between the widgets, this message is not sent.
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'DS_Test.ui'
#
# Created by: PyQt5 UI code generator 5.15.7
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QDragEnterEvent, QDropEvent
class MyButton(QtWidgets.QPushButton):
def mouseMoveEvent(self, event):
btn_img = self.grab()
painter = QtGui.QPainter(btn_img)
painter.setCompositionMode(painter.CompositionMode_DestinationIn)
painter.fillRect(btn_img.rect(), QtGui.QColor(0, 0, 0, 150))
painter.end()
data = QtCore.QMimeData()
drag = QtGui.QDrag(self)
drag.setMimeData(data)
drag.setPixmap(btn_img)
drag.setHotSpot(event.pos())
self._pos = event.pos()
drag.exec_(QtCore.Qt.CopyAction)
super(MyButton, self).mouseMoveEvent(event)
class MyFrame(QtWidgets.QFrame):
def __init__(self, parent):
super().__init__(parent)
self.setAcceptDrops(True)
def dragEnterEvent(self, e: QDragEnterEvent):
e.accept()
def dragMoveEvent(self, e):
e.accept()
def dropEvent(self, e: QDropEvent):
self.parent().dropEvent(e)
class MyQDialog(QtWidgets.QDialog):
def __init__(self):
super().__init__()
self.setAcceptDrops(True)
def dropEvent(self, e: QDropEvent):
print("dropEvent - is done")
e.accept()
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(1051, 800)
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalFrame = MyFrame(Dialog)
self.horizontalFrame.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 211), stop:0.166 rgba(255, 255, 0, 211), stop:0.333 rgba(0, 255, 0, 211), stop:0.5 rgba(0, 255, 255, 211), stop:0.666 rgba(0, 0, 255, 211), stop:0.833 rgba(255, 0, 255, 211), stop:1 rgba(255, 0, 0, 211));")
self.horizontalFrame.setObjectName("horizontalFrame")
self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.horizontalFrame)
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
self.pushButton_3 = MyButton(self.horizontalFrame)
self.pushButton_3.setObjectName("pushButton_3")
self.horizontalLayout_6.addWidget(self.pushButton_3)
self.pushButton_2 = MyButton(self.horizontalFrame)
self.pushButton_2.setObjectName("pushButton_2")
self.horizontalLayout_6.addWidget(self.pushButton_2)
self.pushButton = MyButton(self.horizontalFrame)
self.pushButton.setObjectName("pushButton")
self.horizontalLayout_6.addWidget(self.pushButton)
self.verticalLayout.addWidget(self.horizontalFrame)
self.horizontalFrame_2 = MyFrame(Dialog)
self.horizontalFrame_2.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(9, 41, 4, 255), stop:0.085 rgba(2, 79, 0, 255), stop:0.19 rgba(50, 147, 22, 255), stop:0.275 rgba(236, 191, 49, 255), stop:0.39 rgba(243, 61, 34, 255), stop:0.555 rgba(135, 81, 60, 255), stop:0.667 rgba(121, 75, 255, 255), stop:0.825 rgba(164, 255, 244, 255), stop:0.885 rgba(104, 222, 71, 255), stop:1 rgba(93, 128, 0, 255));")
self.horizontalFrame_2.setObjectName("horizontalFrame_2")
self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.horizontalFrame_2)
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
self.verticalLayout.addWidget(self.horizontalFrame_2)
self.horizontalFrame_3 = MyFrame(Dialog)
self.horizontalFrame_3.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(0, 0, 0, 255), stop:0.05 rgba(14, 8, 73, 255), stop:0.36 rgba(28, 17, 145, 255), stop:0.6 rgba(126, 14, 81, 255), stop:0.75 rgba(234, 11, 11, 255), stop:0.79 rgba(244, 70, 5, 255), stop:0.86 rgba(255, 136, 0, 255), stop:0.935 rgba(239, 236, 55, 255));")
self.horizontalFrame_3.setObjectName("horizontalFrame_3")
self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.horizontalFrame_3)
self.horizontalLayout_8.setObjectName("horizontalLayout_8")
self.verticalLayout.addWidget(self.horizontalFrame_3)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton_3.setText(_translate("Dialog", "PushButton"))
self.pushButton_2.setText(_translate("Dialog", "PushButton"))
self.pushButton.setText(_translate("Dialog", "PushButton"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Dialog = MyQDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
As recommended in the comment, I added dragEnterEvent and dragMoveEvent to MyQDialog. Now everything works the way I want it to. Here is the corrected code
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'DS_Test.ui'
#
# Created by: PyQt5 UI code generator 5.15.7
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QDragEnterEvent, QDropEvent
class MyButton(QtWidgets.QPushButton):
def mouseMoveEvent(self, event):
btn_img = self.grab()
painter = QtGui.QPainter(btn_img)
painter.setCompositionMode(painter.CompositionMode_DestinationIn)
painter.fillRect(btn_img.rect(), QtGui.QColor(0, 0, 0, 150))
painter.end()
data = QtCore.QMimeData()
drag = QtGui.QDrag(self)
drag.setMimeData(data)
drag.setPixmap(btn_img)
drag.setHotSpot(event.pos())
self._pos = event.pos()
drag.exec_(QtCore.Qt.CopyAction)
super(MyButton, self).mouseMoveEvent(event)
class MyFrame(QtWidgets.QFrame):
def __init__(self, parent):
super().__init__(parent)
self.setAcceptDrops(True)
def dragEnterEvent(self, e: QDragEnterEvent):
e.accept()
def dragMoveEvent(self, e):
e.accept()
def dropEvent(self, e: QDropEvent):
self.parent().dropEvent(e)
class MyQDialog(QtWidgets.QDialog):
def __init__(self):
super().__init__()
self.setAcceptDrops(True)
def dragEnterEvent(self, e: QDragEnterEvent):
e.accept()
def dragMoveEvent(self, e):
e.accept()
def dropEvent(self, e: QDropEvent):
print("dropEvent - is done")
e.accept()
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(1051, 800)
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalFrame = MyFrame(Dialog)
self.horizontalFrame.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 211), stop:0.166 rgba(255, 255, 0, 211), stop:0.333 rgba(0, 255, 0, 211), stop:0.5 rgba(0, 255, 255, 211), stop:0.666 rgba(0, 0, 255, 211), stop:0.833 rgba(255, 0, 255, 211), stop:1 rgba(255, 0, 0, 211));")
self.horizontalFrame.setObjectName("horizontalFrame")
self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.horizontalFrame)
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
self.pushButton_3 = MyButton(self.horizontalFrame)
self.pushButton_3.setObjectName("pushButton_3")
self.horizontalLayout_6.addWidget(self.pushButton_3)
self.pushButton_2 = MyButton(self.horizontalFrame)
self.pushButton_2.setObjectName("pushButton_2")
self.horizontalLayout_6.addWidget(self.pushButton_2)
self.pushButton = MyButton(self.horizontalFrame)
self.pushButton.setObjectName("pushButton")
self.horizontalLayout_6.addWidget(self.pushButton)
self.verticalLayout.addWidget(self.horizontalFrame)
self.horizontalFrame_2 = MyFrame(Dialog)
self.horizontalFrame_2.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(9, 41, 4, 255), stop:0.085 rgba(2, 79, 0, 255), stop:0.19 rgba(50, 147, 22, 255), stop:0.275 rgba(236, 191, 49, 255), stop:0.39 rgba(243, 61, 34, 255), stop:0.555 rgba(135, 81, 60, 255), stop:0.667 rgba(121, 75, 255, 255), stop:0.825 rgba(164, 255, 244, 255), stop:0.885 rgba(104, 222, 71, 255), stop:1 rgba(93, 128, 0, 255));")
self.horizontalFrame_2.setObjectName("horizontalFrame_2")
self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.horizontalFrame_2)
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
self.verticalLayout.addWidget(self.horizontalFrame_2)
self.horizontalFrame_3 = MyFrame(Dialog)
self.horizontalFrame_3.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(0, 0, 0, 255), stop:0.05 rgba(14, 8, 73, 255), stop:0.36 rgba(28, 17, 145, 255), stop:0.6 rgba(126, 14, 81, 255), stop:0.75 rgba(234, 11, 11, 255), stop:0.79 rgba(244, 70, 5, 255), stop:0.86 rgba(255, 136, 0, 255), stop:0.935 rgba(239, 236, 55, 255));")
self.horizontalFrame_3.setObjectName("horizontalFrame_3")
self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.horizontalFrame_3)
self.horizontalLayout_8.setObjectName("horizontalLayout_8")
self.verticalLayout.addWidget(self.horizontalFrame_3)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton_3.setText(_translate("Dialog", "PushButton"))
self.pushButton_2.setText(_translate("Dialog", "PushButton"))
self.pushButton.setText(_translate("Dialog", "PushButton"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Dialog = MyQDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
I'm trying to pad a numpy array with a tuple (the array itself has only tuples)...all I can find is padding an array with 0s or 1s, which I can get to work, but that doesn't help me. Is it possible to pad with a tuple?
The crucial line is :
cells = np.pad(cells, pad_width=1, mode='constant', constant_values=material)
Replacing material, which is a 4-tuple, with a 0 works fine...but I really need it to be a tuple.
I get the error message:
operands could not be broadcast together with remapped shapes [original->remapped]: (4,) and requested shape (2,2)
Here is the code I am using, but using 0s and 1s instead:
import numpy as np
side_len = 3
a = [1 for x in range(9)]
a = np.array(a)
a = a.reshape(side_len,side_len)
a = np.pad(a, pad_width=1, mode='constant', constant_values=0)
The goal is instead of a list of 1s, to pass a list of tuples, and instead of a constant_values=0, to have constant_values=material, where material is an arbitrary 4-tuple.
A flat list of tuples are passed to this function (the function is not shown here), eg:
[(0, 0, 255, 255), (0, 0, 255, 255), (0, 0, 255, 255), (0, 0, 255, 255), (0, 0, 255, 255), (0, 0, 255, 255), (0, 0, 255, 255), (0, 0, 255, 255), (0, 0, 255, 255)]
Which I convert to a numpy array using:
cells = np.array(cells, dtype='i,i,i,i').reshape(side_len,side_len)
Perhaps this is wonky, but the rest of my program just uses lists, I don't need numpy for it; but for this padding issue, I originally was manually iterating over my flat list and doing the padding, which took forever as the list grew, so I thought I'd try numpy because it might be faster.
the solution was:
import numpy as np
side_len = 3
material = (0,0,0,255)
a = [(255,0,0,255) for x in range(9)]
a = np.array(a,dtype='i,i,i,i').reshape(side_len,side_len)
_material = np.array(material,dtype='i,i,i,i')
a = np.pad(a, pad_width=1, mode='constant', constant_values=_material)
a
array([[( 0, 0, 0, 255), ( 0, 0, 0, 255), ( 0, 0, 0, 255),
( 0, 0, 0, 255), ( 0, 0, 0, 255)],
[( 0, 0, 0, 255), (255, 0, 0, 255), (255, 0, 0, 255),
(255, 0, 0, 255), ( 0, 0, 0, 255)],
[( 0, 0, 0, 255), (255, 0, 0, 255), (255, 0, 0, 255),
(255, 0, 0, 255), ( 0, 0, 0, 255)],
[( 0, 0, 0, 255), (255, 0, 0, 255), (255, 0, 0, 255),
(255, 0, 0, 255), ( 0, 0, 0, 255)],
[( 0, 0, 0, 255), ( 0, 0, 0, 255), ( 0, 0, 0, 255),
( 0, 0, 0, 255), ( 0, 0, 0, 255)]],
dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4'), ('f3', '<i4')])
png files are usually index values assosiated with a default palette. by default, index values can be read by PIL image, for example:
import tensorflow as tf
from PIL import Image
import numpy as np
path = '1.png'
image1 = Image.open(path)
print(image1.mode)
array1 = np.array(image1)
print(array1.shape)
print(set(list(array1.reshape(-1))))
the results:
P
(1024, 543)
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
index can be converted to palette colors:
image2 = image1.convert('RGB')
print(image2.mode)
array2 = np.array(image2)
print(array2.shape)
print(set([tuple(x) for x in list(array2.reshape(-1, 3))]))
the results are
RGB
(1024, 543, 3)
{(0, 255, 255), (255, 255, 0), (0, 0, 255), (85, 255, 170), (170, 255, 85), (255, 0, 0), (255, 170, 0), (0, 170, 255), (0, 85, 255), (255, 85, 0), (0, 0, 170)}
the question is, by default, tensorflow 2.x API read palette colors, is there a way to read the index values?
tensor = tf.io.read_file(path)
tensor = tf.image.decode_png(tensor, channels=3)
array3 = tensor.numpy()
print(array3.shape)
print(set([tuple(x) for x in list(array3.reshape(-1, 3))]))
(1024, 543, 3)
{(0, 255, 255), (255, 255, 0), (0, 0, 255), (85, 255, 170), (170, 255, 85), (255, 0, 0), (255, 170, 0), (0, 170, 255), (0, 85, 255), (255, 85, 0), (0, 0, 170)}
my temporary solution is to remove all the palette assosiated with png files. Still looking for more efficient solutions
from PIL import Image
import numpy as np
img = Image.open('1.png')
img = np.array(img)
img = Image.fromarray(img)
img.save('2.png')
Ideal solution
A clean solution would be to re-implement a custom op to decode a PNG without palette conversion.
Currently, the palette conversion in TF for the decode_png-op is done at core level:
// convert palette to rgb(a) if needs be.
if (context->color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(context->png_ptr);
Work-around solution
(TF2.X)
As you've mentioned PIL in your sample code, you could wrap the PIL-call with tf.py_function in order to get the desired behavior, like:
def read_png(mask):
def read_fn(p):
return np.asarray(Image.open(p.numpy().decode()))
return tf.py_function(read_fn, [mask], tf.uint8)
and then read a paletted PNG-image without automatic palette application, like:
img = read_png(path)
img= img.numpy()
print(img.shape)
print(set(list(img.reshape(-1))))
Sample output
(1024, 543)
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
Note: in TF1.X this works only in graph-mode, and you would have to use tf.py_func to wrap the TF around PIL-function (+ some minor changes).
what are the interpretation values in the"" points assignment. all I want is a "plane jane" line where I can manipulate the length and width. Any help will greatly appreciated.
var line = new Kinetic.Line({
x: 100,
y: 50,
points: [73, 70, 340, 23, 450, 60, 500, 20],
stroke: 'red',
tension: 1
});
The points array is a series of x,y coordinates:
// [73, 70, 340, 23, 450, 60, 500, 20],
{x:73,y:70},
{x:340,y:23},
{x:450,y:60},
{x:500,y:20}
This is your "plain jane" line:
// draw a black line from 25,25 to 100,50 and width of 5
var line = new Kinetic.Line({
points:[25,25, 100,50],
y:100,
stroke: 'black',
strokeWidth: 5
});
I made a multi-stop gradient mix-in that simply puts #arguments for all the vendor prefixes for *-linear-gradient. It works, put I'm annoyed when I define a gradient with many stops, I have to put everything on one line when using the mixin, like this:
.gradientMultiple(~'top, rgba(255, 255, 255, 1) 0%, rgba(254, 254, 254, 1) 16%, rgba(252, 252, 252, 1) 36%, rgba(239, 239, 239, 1) 66%, rgba(18, 34, 106, 1) 66%, rgba(13, 31, 136, 1) 84%');
I'd like to put the function parameter on multiple lines like this for readability, but it generates a parse error:
.gradientMultiple(~'top,
rgba(255, 255, 255, 1) 0%,
rgba(254, 254, 254, 1) 16%,
rgba(252, 252, 252, 1) 36%,
rgba(239, 239, 239, 1) 66%,
rgba(18, 34, 106, 1) 66%,
rgba(13, 31, 136, 1) 84%
');
Here's the mixin definition:
.gradientMultiple ( ... ) {
background-image: -webkit-linear-gradient(#arguments);
background-image: -moz-linear-gradient(#arguments);
background-image: -ms-linear-gradient(#arguments);
background-image: -o-linear-gradient(#arguments);
background-image: linear-gradient(#arguments);
}
.gradientMultiple(top,
rgba(255, 255, 255, 1) 0%,
rgba(254, 254, 254, 1) 16%,
rgba(252, 252, 252, 1) 36%,
rgba(239, 239, 239, 1) 66%,
rgba( 18, 34, 106, 1) 66%,
rgba( 13, 31, 136, 1) 84%;);
Also see:
0
1
2
and finally the lead remark of 3
For use cases when the mixin forces you to supply a string, or you don't want LESS to compute the argument value, you can use a bit of javascript:
(disclaimer: JS evaluation is now deprecated and possibly will be removed in LESS 3/4, so use this only when working with legacy code where no other alternative is available)
.keyframes(~`
"translate, " +
"50% { transform: translateX(calc(50% - 25px)) } " +
"100% { transform: translateX(0px) } "
`);