Support
Quality
Security
License
Reuse
kandi has reviewed vlayout and discovered the below as its top functions. This is intended to give you an instant insight into vlayout implemented functionality, and help decide if they suit your requirements.
Provide default common layout implementation, decouple the View and Layout. Default layout implementations are: LinearLayoutHelper: provide linear layout as LinearLayoutManager. GridLayoutHelper: provide grid layout as GridLayoutManager, but with more feature. FixLayoutHelper: fix the view at certain position of screen, the view does not scroll with whole page. ScrollFixLayoutHelper: fix the view at certain position of screen, but the view does not show until it scrolls to it position. FloatLayoutHelper: float the view on top of page, user can drag and drop it. ColumnLayoutHelper: perform like GridLayoutHelper but layouts all child views in one line. SingleLayoutHelper: contain only one child view. OnePlusNLayoutHelper: a custom layout with one child view layouted at left and the others at right, you may not need this. StickyLayoutHelper: scroll the view when its position is inside the screen, but fix the view at start or end when its position is outside the screen. StaggeredGridLayoutHelper: provide waterfall like layout as StaggeredGridLayoutManager.
LayoutHelpers provided by default can be generally divided into two categories. One is non-fix LayoutHelper such as LinearLayoutHelper, GridLayoutHelper, etc which means the children of these LayoutHelper will be layouted in the flow of parent container and will be scrolled with the container scrolling. While the other is fix LayoutHelper which means the child of these is always fix in parent container.
Import Library
compile ('com.alibaba.android:vlayout:1.2.8@aar') {
transitive = true
}
Initialize LayoutManager
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
final VirtualLayoutManager layoutManager = new VirtualLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
Initialize recycled pool's size
RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
recyclerView.setRecycledViewPool(viewPool);
viewPool.setMaxRecycledViews(0, 10);
Set Adapters
DelegateAdapter delegateAdapter = new DelegateAdapter(layoutManager, hasConsistItemType);
recycler.setAdapter(delegateAdapter);
// Then you can set sub- adapters
delegateAdapter.setAdapters(adapters);
// or
CustomAdapter adapter = new CustomAdapter(data, new GridLayoutHelper());
delegateAdapter.addAdapter(adapter);
// call notify change when data changes
adapter.notifyDataSetChanged();
Config proguard
-keepattributes InnerClasses
-keep class com.alibaba.android.vlayout.ExposeLinearLayoutManagerEx { *; }
-keep class android.support.v7.widget.RecyclerView$LayoutParams { *; }
-keep class android.support.v7.widget.RecyclerView$ViewHolder { *; }
-keep class android.support.v7.widget.ChildHelper { *; }
-keep class android.support.v7.widget.ChildHelper$Bucket { *; }
-keep class android.support.v7.widget.RecyclerView$LayoutManager { *; }
qTableview sorting with PandasModel
from PyQt5 import QtCore, QtWidgets
import pandas as pd
import numpy as np
class NumpyArrayModel(QtCore.QAbstractTableModel):
def __init__(self, array, headers, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent=parent)
self._array = array
self._headers = headers
self.r, self.c = np.shape(self.array)
@property
def array(self):
return self._array
@property
def headers(self):
return self._headers
def rowCount(self, parent=QtCore.QModelIndex()):
return self.r
def columnCount(self, parent=QtCore.QModelIndex()):
return self.c
def headerData(self, p_int, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
if p_int < len(self.headers):
return self.headers[p_int]
elif orientation == QtCore.Qt.Vertical:
return p_int + 1
return
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return None
row = index.row()
column = index.column()
if row < 0 or row >= self.rowCount():
return None
if column < 0 or column >= self.columnCount():
return None
if role == QtCore.Qt.DisplayRole:
return float(self.array[row, column])
return None
def setData(self, index, value, role):
if not index.isValid():
return False
if role != QtCore.Qt.EditRole:
return False
row = index.row()
column = index.column()
if row < 0 or row >= self.rowCount():
return False
if column < 0 or column >= self.columnCount():
return False
self.array.values[row][column] = value
self.dataChanged.emit(index, index)
return True
def sort(self, column, order):
self.layoutAboutToBeChanged.emit()
argsort = self.array[:, column].argsort()
if order == QtCore.Qt.DescendingOrder:
argsort = argsort[::-1]
self._array = self.array[argsort]
self.layoutChanged.emit()
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent=None)
vLayout = QtWidgets.QVBoxLayout(self)
hLayout = QtWidgets.QHBoxLayout()
self.pathLE = QtWidgets.QLineEdit(self)
hLayout.addWidget(self.pathLE)
self.loadBtn = QtWidgets.QPushButton("Select File", self)
hLayout.addWidget(self.loadBtn)
vLayout.addLayout(hLayout)
self.pandasTv = QtWidgets.QTableView(self)
vLayout.addWidget(self.pandasTv)
self.loadBtn.clicked.connect(self.loadFile)
self.pandasTv.setSortingEnabled(True)
def loadFile(self):
fileName, _ = QtWidgets.QFileDialog.getOpenFileName(
self, "Open File", "", "CSV Files (*.csv)"
)
self.pathLE.setText(fileName)
if fileName:
df = pd.read_csv(fileName)
array = np.array(df.values)
headers = df.columns.tolist()
model = NumpyArrayModel(array, headers)
self.pandasTv.setModel(model)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
Need to connect two nodes of different circle packed layout in d3
const data = {
name: "root",
children: [
{
name: "A",
children: [
{name: "A1", value: 7}, {name: "A2", value: 8}, {name: "A3", value: 9}, {name: "A4", value: 10}, {name: "A5", value: 10}
]
},
{
name: "B",
children: [
{name: "B1", value: 11}, {name: "B2", value: 7}, {name: "B3", value: 8},
]
},
{
name: "C",
value: 10
},
{
name: "D",
value: 10
},
{
name: "E",
value: 10
}
],
links: [{from: "A3", to: "C"}, {from: "A2", to: "E"}, {from: "B1", to: "D"}, {from: "B2", to: "B3"}, {from: "B1", to: "C"}]
};
const svg = d3.select("svg");
const pack = data => d3.pack()
.size([400, 400])
.padding(20)
(d3.hierarchy(data)
.sum(d => d.value * 2.5)
.sort((a, b) => b.value - a.value));
const root = pack(data);
const nodes = root.descendants().slice(1);
console.log(nodes);
const container = svg.append('g')
.attr('transform', 'translate(0,-50)')
const nodeElements = container
.selectAll("circle")
.data(nodes);
nodeElements.enter()
.append("circle")
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.attr('r', d => d.value)
.attr("fill", d => d.children ? "#ffe0e0" : "#ffefef")
.attr('stroke', 'black')
const labelElements = container
.selectAll("text")
.data(nodes);
labelElements.enter()
.append("text")
.text(d => d.data.name)
.attr('x', d => d.x)
.attr('y', d => d.children ? d.y + d.value + 10 : d.y)
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'middle')
.style('fill', 'black')
const linkElements = container.selectAll('path.link')
.data(data.links);
const linkPath = d => {
const from = nodes.find(n => n.data.name === d.from);
const to = nodes.find(n => n.data.name === d.to);
const length = Math.hypot(from.x - to.x, from.y - to.y);
const fd = from.value / length;
const fx = from.x + (to.x - from.x) * fd;
const fy = from.y + (to.y - from.y) * fd;
const td = to.value / length;
const tx = to.x + (from.x - to.x) * td;
const ty = to.y + (from.y - to.y) * td;
return `M ${fx},${fy} L ${tx},${ty}`;
};
linkElements.enter()
.append('path')
.classed('link', true)
.attr('d', linkPath)
.attr('marker-start', 'url(#arrowhead-from)')
.attr('marker-end', 'url(#arrowhead-to)');
text {
font-family: "Ubuntu";
font-size: 12px;
}
.link {
stroke: blue;
fill: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
<svg width="400" height="400">
<defs>
<marker id="arrowhead-to" markerWidth="10" markerHeight="7"
refX="10" refY="3.5" orient="auto">
<polygon fill="blue" points="0 0, 10 3.5, 0 7" />
</marker>
<marker id="arrowhead-from" markerWidth="10" markerHeight="7"
refX="0" refY="3.5" orient="auto">
<polygon fill="blue" points="10 0, 0 3.5, 10 7" />
</marker>
</defs>
</svg>
-----------------------
const data = {
name: "root",
children: [
{
name: "A",
children: [
{name: "A1", value: 7}, {name: "A2", value: 8}, {name: "A3", value: 9}, {name: "A4", value: 10}, {name: "A5", value: 10}
]
},
{
name: "B",
children: [
{name: "B1", value: 11}, {name: "B2", value: 7}, {name: "B3", value: 8},
]
},
{
name: "C",
value: 10
},
{
name: "D",
value: 10
},
{
name: "E",
value: 10
}
],
links: [{from: "A3", to: "C"}, {from: "A2", to: "E"}, {from: "B1", to: "D"}, {from: "B2", to: "B3"}, {from: "B1", to: "C"}]
};
const svg = d3.select("svg");
const pack = data => d3.pack()
.size([400, 400])
.padding(20)
(d3.hierarchy(data)
.sum(d => d.value * 2.5)
.sort((a, b) => b.value - a.value));
const root = pack(data);
const nodes = root.descendants().slice(1);
console.log(nodes);
const container = svg.append('g')
.attr('transform', 'translate(0,-50)')
const nodeElements = container
.selectAll("circle")
.data(nodes);
nodeElements.enter()
.append("circle")
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.attr('r', d => d.value)
.attr("fill", d => d.children ? "#ffe0e0" : "#ffefef")
.attr('stroke', 'black')
const labelElements = container
.selectAll("text")
.data(nodes);
labelElements.enter()
.append("text")
.text(d => d.data.name)
.attr('x', d => d.x)
.attr('y', d => d.children ? d.y + d.value + 10 : d.y)
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'middle')
.style('fill', 'black')
const linkElements = container.selectAll('path.link')
.data(data.links);
const linkPath = d => {
const from = nodes.find(n => n.data.name === d.from);
const to = nodes.find(n => n.data.name === d.to);
const length = Math.hypot(from.x - to.x, from.y - to.y);
const fd = from.value / length;
const fx = from.x + (to.x - from.x) * fd;
const fy = from.y + (to.y - from.y) * fd;
const td = to.value / length;
const tx = to.x + (from.x - to.x) * td;
const ty = to.y + (from.y - to.y) * td;
return `M ${fx},${fy} L ${tx},${ty}`;
};
linkElements.enter()
.append('path')
.classed('link', true)
.attr('d', linkPath)
.attr('marker-start', 'url(#arrowhead-from)')
.attr('marker-end', 'url(#arrowhead-to)');
text {
font-family: "Ubuntu";
font-size: 12px;
}
.link {
stroke: blue;
fill: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
<svg width="400" height="400">
<defs>
<marker id="arrowhead-to" markerWidth="10" markerHeight="7"
refX="10" refY="3.5" orient="auto">
<polygon fill="blue" points="0 0, 10 3.5, 0 7" />
</marker>
<marker id="arrowhead-from" markerWidth="10" markerHeight="7"
refX="0" refY="3.5" orient="auto">
<polygon fill="blue" points="10 0, 0 3.5, 10 7" />
</marker>
</defs>
</svg>
-----------------------
const data = {
name: "root",
children: [
{
name: "A",
children: [
{name: "A1", value: 7}, {name: "A2", value: 8}, {name: "A3", value: 9}, {name: "A4", value: 10}, {name: "A5", value: 10}
]
},
{
name: "B",
children: [
{name: "B1", value: 11}, {name: "B2", value: 7}, {name: "B3", value: 8},
]
},
{
name: "C",
value: 10
},
{
name: "D",
value: 10
},
{
name: "E",
value: 10
}
],
links: [{from: "A3", to: "C"}, {from: "A2", to: "E"}, {from: "B1", to: "D"}, {from: "B2", to: "B3"}, {from: "B1", to: "C"}]
};
const svg = d3.select("svg");
const pack = data => d3.pack()
.size([400, 400])
.padding(20)
(d3.hierarchy(data)
.sum(d => d.value * 2.5)
.sort((a, b) => b.value - a.value));
const root = pack(data);
const nodes = root.descendants().slice(1);
console.log(nodes);
const container = svg.append('g')
.attr('transform', 'translate(0,-50)')
const nodeElements = container
.selectAll("circle")
.data(nodes);
nodeElements.enter()
.append("circle")
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.attr('r', d => d.value)
.attr("fill", d => d.children ? "#ffe0e0" : "#ffefef")
.attr('stroke', 'black')
const labelElements = container
.selectAll("text")
.data(nodes);
labelElements.enter()
.append("text")
.text(d => d.data.name)
.attr('x', d => d.x)
.attr('y', d => d.children ? d.y + d.value + 10 : d.y)
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'middle')
.style('fill', 'black')
const linkElements = container.selectAll('path.link')
.data(data.links);
const linkPath = d => {
const from = nodes.find(n => n.data.name === d.from);
const to = nodes.find(n => n.data.name === d.to);
const length = Math.hypot(from.x - to.x, from.y - to.y);
const fd = from.value / length;
const fx = from.x + (to.x - from.x) * fd;
const fy = from.y + (to.y - from.y) * fd;
const td = to.value / length;
const tx = to.x + (from.x - to.x) * td;
const ty = to.y + (from.y - to.y) * td;
return `M ${fx},${fy} L ${tx},${ty}`;
};
linkElements.enter()
.append('path')
.classed('link', true)
.attr('d', linkPath)
.attr('marker-start', 'url(#arrowhead-from)')
.attr('marker-end', 'url(#arrowhead-to)');
text {
font-family: "Ubuntu";
font-size: 12px;
}
.link {
stroke: blue;
fill: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
<svg width="400" height="400">
<defs>
<marker id="arrowhead-to" markerWidth="10" markerHeight="7"
refX="10" refY="3.5" orient="auto">
<polygon fill="blue" points="0 0, 10 3.5, 0 7" />
</marker>
<marker id="arrowhead-from" markerWidth="10" markerHeight="7"
refX="0" refY="3.5" orient="auto">
<polygon fill="blue" points="10 0, 0 3.5, 10 7" />
</marker>
</defs>
</svg>
How to open the youtube link from a youtube video embed in a PyQt5 Widget in Python?
import sys
from PyQt5.QtCore import QUrl, Qt, pyqtSlot
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QVBoxLayout, QWidget
from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineSettings, QWebEngineView
popups = []
class Widget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.view = QWebEngineView()
lay = QVBoxLayout(self)
lay.addWidget(self.view)
self.resize(640, 480)
class WebEnginePage(QWebEnginePage):
def createWindow(self, _type):
w = Widget()
w.show()
popups.append(w)
return w.view.page()
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent=None)
self.setWindowTitle("My Awesome App")
central_widget = QWidget()
self.setCentralWidget(central_widget)
label = QLabel("This is a PyQt5 window!", alignment=Qt.AlignCenter)
self.webview = QWebEngineView()
self.page = WebEnginePage()
self.webview.setPage(self.page)
self.webview.settings().setAttribute(
QWebEngineSettings.FullScreenSupportEnabled, True
)
self.webview.load(
QUrl("https://www.youtube.com/embed/g8NVwN0_mks?rel=0&showinfo=0")
)
lay = QVBoxLayout(central_widget)
lay.addWidget(label)
lay.addWidget(self.webview)
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
if __name__ == "__main__":
main()
GridLayout position in PyQt
gridLayout.setColumnStretch(1, 1)
How make QListWidgetItem autosize to its content, and fit into its QListWidget
widget = customWidget(var[0], var[1], var[2])
hint = widget.sizeHint()
hint.setWidth(-1)
item.setSizeHint(hint)
Implementing PyQt5 "docking/undocking" mechamism for QStackedWidget: unpredictable Access Violation
def closeEvent(self, event: QtGui.QCloseEvent) -> NoReturn:
if self.windowFlags() & Qt.Window:
# Change windowFlags back to Qt.QWidget
self.setWindowFlags(Qt.Widget)
# We need to ignore QCloseEvent here
event.ignore()
self.returnToQStackedWidgetSignal.emit()
else:
event.accept()
PyQt5 Combining QVBoxLayout and QStackedLayout
class MyCustomWidget(QWidget):
def __init__(self):
super().__init__()
self.my_combo_box = QComboBox(self)
self.vlayout = QVBoxLayout(self)
self.slayout = QStackedLayout()
self.vlayout.addWidget(self.my_combo_box)
# add stacked layout to self.vlayout (only need to be done once).
self.vlayout.addLayout(self.slayout)
self.graphWidget = {}
# self.widget isn't doing anything in your code so I commented out this line
# self.widget = QWidget()
# Add signal-slot connection to show correct graph when current index in combo box is changed.
self.my_combo_box.currentIndexChanged.connect(self.slayout.setCurrentIndex)
def add_new_graphics(self, name, x, y):
self.my_combo_box.addItem(name)
self.graphWidget[name] = pg.PlotWidget()
self.graphWidget[name].plot(x, y)
self.slayout.addWidget(self.graphWidget[name])
Writing open file code after converted UI file to Python - QTabWidget
def loading(self):
options = QtWidgets.QFileDialog.Options()
fileName, _ = QtWidgets.QFileDialog.getOpenFileName(None, "Open File", "C:/",
"CSV Files (*.csv)", options=options);
Signal QscrollArea
class Widget(QWidget):
def __init__(self, parent= None):
# ....
# note that the scroll area is now an instance member
self.scroll = QScrollArea()
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.scroll.setWidget(widget)
self.scroll.verticalScrollBar().rangeChanged.connect(self.checkScrollBarRange)
vLayout = QVBoxLayout(self)
vLayout.addWidget(self.scroll)
self.setLayout(vLayout)
# the next is important when resizing the widget containing the scroll area
self.scroll.installEventFilter(self)
def eventFilter(self, source, event):
if source == self.scroll and event.type() == QEvent.Resize:
self.checkScrollBarRange()
return super().eventFilter(source, event)
def checkScrollBarRange(self):
if (self.scroll.verticalScrollBarPolicy() != Qt.ScrollBarAlwaysOff and
self.scroll.verticalScrollBar().maximum()):
print('vertical scroll bar IS visible')
else:
print('vertical scroll bar NOT visible')
PyQt5: Program crashes after a certain number of push buttons is added into a GridLayout
import sys
from PyQt5.Qt import *
class Widget(QWidget):
def __init__(self):
super().__init__()
self.midColLayout = QVBoxLayout()
self.graphWidget = QWidget(self) ## self
self.graphWidget.setStyleSheet("background-color: white; padding:0px;")
self.graphWidget.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
self.vLayout = QVBoxLayout()
self.hLayout = QHBoxLayout()
self.gridLayout = QGridLayout()
self.gridLayout.setSpacing(0)
self.hLayout.addLayout(self.gridLayout)
self.vLayout.addLayout(self.hLayout)
self.buttons = []
for x in range(0, 80): # If I put 81, then the program crashes
l = []
for y in range(0, 90): # If I put 91, then the program crashes
self.button = QPushButton()
l.append(self.button)
self.gridLayout.addWidget(self.button, x, y)
self.buttons.append(l)
self.graphWidget.setLayout(self.vLayout)
#? self.midColLayout.addWidget(self.mapLabel)
self.midColLayout.addWidget(self.graphWidget)
if __name__ == '__main__':
myapp = QApplication(sys.argv)
mywin = Widget()
mywin.resize(400, 400)
mywin.show()
sys.exit(myapp.exec_())
import sys
from PyQt5.Qt import *
class Widget(QWidget):
def __init__(self):
super().__init__()
self.midColLayout = QVBoxLayout()
self.graphWidget = QWidget(self) ## self
self.graphWidget.setStyleSheet("background-color: white; padding:0px;")
self.graphWidget.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
self.vLayout = QVBoxLayout(self) # +++ self
self.hLayout = QHBoxLayout()
self.gridLayout = QGridLayout()
self.gridLayout.setSpacing(0)
self.hLayout.addLayout(self.gridLayout)
self.vLayout.addLayout(self.hLayout)
self.buttons = []
for x in range(0, 80): # If I put 81, then the program crashes
l = []
for y in range(0, 90): # If I put 91, then the program crashes
self.button = QPushButton()
l.append(self.button)
self.gridLayout.addWidget(self.button, x, y)
self.buttons.append(l)
# self.graphWidget.setLayout(self.vLayout) # ---
#? self.midColLayout.addWidget(self.mapLabel)
self.midColLayout.addWidget(self.graphWidget)
if __name__ == '__main__':
myapp = QApplication(sys.argv)
mywin = Widget()
mywin.resize(400, 400)
mywin.show()
sys.exit(myapp.exec_())
-----------------------
import sys
from PyQt5.Qt import *
class Widget(QWidget):
def __init__(self):
super().__init__()
self.midColLayout = QVBoxLayout()
self.graphWidget = QWidget(self) ## self
self.graphWidget.setStyleSheet("background-color: white; padding:0px;")
self.graphWidget.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
self.vLayout = QVBoxLayout()
self.hLayout = QHBoxLayout()
self.gridLayout = QGridLayout()
self.gridLayout.setSpacing(0)
self.hLayout.addLayout(self.gridLayout)
self.vLayout.addLayout(self.hLayout)
self.buttons = []
for x in range(0, 80): # If I put 81, then the program crashes
l = []
for y in range(0, 90): # If I put 91, then the program crashes
self.button = QPushButton()
l.append(self.button)
self.gridLayout.addWidget(self.button, x, y)
self.buttons.append(l)
self.graphWidget.setLayout(self.vLayout)
#? self.midColLayout.addWidget(self.mapLabel)
self.midColLayout.addWidget(self.graphWidget)
if __name__ == '__main__':
myapp = QApplication(sys.argv)
mywin = Widget()
mywin.resize(400, 400)
mywin.show()
sys.exit(myapp.exec_())
import sys
from PyQt5.Qt import *
class Widget(QWidget):
def __init__(self):
super().__init__()
self.midColLayout = QVBoxLayout()
self.graphWidget = QWidget(self) ## self
self.graphWidget.setStyleSheet("background-color: white; padding:0px;")
self.graphWidget.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
self.vLayout = QVBoxLayout(self) # +++ self
self.hLayout = QHBoxLayout()
self.gridLayout = QGridLayout()
self.gridLayout.setSpacing(0)
self.hLayout.addLayout(self.gridLayout)
self.vLayout.addLayout(self.hLayout)
self.buttons = []
for x in range(0, 80): # If I put 81, then the program crashes
l = []
for y in range(0, 90): # If I put 91, then the program crashes
self.button = QPushButton()
l.append(self.button)
self.gridLayout.addWidget(self.button, x, y)
self.buttons.append(l)
# self.graphWidget.setLayout(self.vLayout) # ---
#? self.midColLayout.addWidget(self.mapLabel)
self.midColLayout.addWidget(self.graphWidget)
if __name__ == '__main__':
myapp = QApplication(sys.argv)
mywin = Widget()
mywin.resize(400, 400)
mywin.show()
sys.exit(myapp.exec_())
QUESTION
qTableview sorting with PandasModel
Asked 2021-May-25 at 16:54I am using Pandasmodel
for qTableview. I have converted data to numpy array. Now, I am trying to sort the table columns, but got the following attribute error:numpy.ndarray object has no attribute column
. I have used numpy to convert dataframe because numpy is quite faster than panda to show datas in tableview.
How can I set with numpyarray for sorting the tableView?
pandasModel.py
from PyQt5 import QtCore
import pandas as pd
import numpy as np
class PandasModel(QtCore.QAbstractTableModel):
def __init__(self, df = pd.DataFrame(), parent=None):
QtCore.QAbstractTableModel.__init__(self, parent=parent)
self._df = np.array(df.values) # convert to numpy array
self._cols = df.columns
self.r, self.c = np.shape(self._df)
def headerData(self, p_int, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
return self._cols[p_int]
elif orientation == QtCore.Qt.Vertical:
return p_int+1
return None
def data(self, index, role=QtCore.Qt.DisplayRole):
if index.isValid():
if role == QtCore.Qt.DisplayRole:
return self._df[index.row(),index.column()]
return None
def setData(self, index, value, role):
if not index.isValid():
return False
if role != QtCore.Qt.EditRole:
return False
row = index.row()
if row < 0 or row >= len(self._df.values):
return False
column = index.column()
if column < 0 or column >= self._df.columns.size:
return False
self._df.values[row][column] = value
self.dataChanged.emit(index, index)
return True
def rowCount(self, parent=None):
return self.r
def columnCount(self, parent=QtCore.QModelIndex()):
return self.c
def sort(self, column, order):
colname = self._df.columns.tolist()[column]
self.layoutAboutToBeChanged.emit()
self._df.sort_values(colname, ascending= order == QtCore.Qt.AscendingOrder, inplace=True)
self._df.reset_index(inplace=True, drop=True)
self.layoutChanged.emit()
MainClass.py
from PyQt5 import QtCore, QtGui, QtWidgets
import pandas as pd
from PandasModel import PandasModel
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent=None)
vLayout = QtWidgets.QVBoxLayout(self)
hLayout = QtWidgets.QHBoxLayout()
self.pathLE = QtWidgets.QLineEdit(self)
hLayout.addWidget(self.pathLE)
self.loadBtn = QtWidgets.QPushButton("Select File", self)
hLayout.addWidget(self.loadBtn)
vLayout.addLayout(hLayout)
self.pandasTv = QtWidgets.QTableView(self)
vLayout.addWidget(self.pandasTv)
self.loadBtn.clicked.connect(self.loadFile)
self.pandasTv.setSortingEnabled(True)
def loadFile(self):
fileName, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Open File", "", "CSV Files (*.csv)");
self.pathLE.setText(fileName)
df = pd.read_csv(fileName)
model = PandasModel(df)
self.pandasTv.setModel(model)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
ANSWER
Answered 2021-May-25 at 16:54The problem is that the sort()
method uses pandas logic to sort the rows. To avoid that kind of confusion it is better to create a model based on numpy.array replacing all the pandas logic.
from PyQt5 import QtCore, QtWidgets
import pandas as pd
import numpy as np
class NumpyArrayModel(QtCore.QAbstractTableModel):
def __init__(self, array, headers, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent=parent)
self._array = array
self._headers = headers
self.r, self.c = np.shape(self.array)
@property
def array(self):
return self._array
@property
def headers(self):
return self._headers
def rowCount(self, parent=QtCore.QModelIndex()):
return self.r
def columnCount(self, parent=QtCore.QModelIndex()):
return self.c
def headerData(self, p_int, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
if p_int < len(self.headers):
return self.headers[p_int]
elif orientation == QtCore.Qt.Vertical:
return p_int + 1
return
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return None
row = index.row()
column = index.column()
if row < 0 or row >= self.rowCount():
return None
if column < 0 or column >= self.columnCount():
return None
if role == QtCore.Qt.DisplayRole:
return float(self.array[row, column])
return None
def setData(self, index, value, role):
if not index.isValid():
return False
if role != QtCore.Qt.EditRole:
return False
row = index.row()
column = index.column()
if row < 0 or row >= self.rowCount():
return False
if column < 0 or column >= self.columnCount():
return False
self.array.values[row][column] = value
self.dataChanged.emit(index, index)
return True
def sort(self, column, order):
self.layoutAboutToBeChanged.emit()
argsort = self.array[:, column].argsort()
if order == QtCore.Qt.DescendingOrder:
argsort = argsort[::-1]
self._array = self.array[argsort]
self.layoutChanged.emit()
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent=None)
vLayout = QtWidgets.QVBoxLayout(self)
hLayout = QtWidgets.QHBoxLayout()
self.pathLE = QtWidgets.QLineEdit(self)
hLayout.addWidget(self.pathLE)
self.loadBtn = QtWidgets.QPushButton("Select File", self)
hLayout.addWidget(self.loadBtn)
vLayout.addLayout(hLayout)
self.pandasTv = QtWidgets.QTableView(self)
vLayout.addWidget(self.pandasTv)
self.loadBtn.clicked.connect(self.loadFile)
self.pandasTv.setSortingEnabled(True)
def loadFile(self):
fileName, _ = QtWidgets.QFileDialog.getOpenFileName(
self, "Open File", "", "CSV Files (*.csv)"
)
self.pathLE.setText(fileName)
if fileName:
df = pd.read_csv(fileName)
array = np.array(df.values)
headers = df.columns.tolist()
model = NumpyArrayModel(array, headers)
self.pandasTv.setModel(model)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
Community Discussions, Code Snippets contain sources that include Stack Exchange Network
No vulnerabilities reported
Save this library and start creating your kit
Save this library and start creating your kit