If I set the format of the first column in a ListCtrl to align centre (or align right) nothing happens. It works for the other columns.
This only happens on Windows - I have tested it on Linux and it works fine.
Does anyone know if there is a work-round or other solution?
Here is an example based on code found at http://zetcode.com/wxpython/
import wx
import sys
packages = [('jessica alba', 'pomona', '1981'), ('sigourney weaver', 'new york', '1949'),
('angelina jolie', 'los angeles', '1975'), ('natalie portman', 'jerusalem', '1981'),
('rachel weiss', 'london', '1971'), ('scarlett johansson', 'new york', '1984' )]
class Actresses(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(380, 230))
hbox = wx.BoxSizer(wx.HORIZONTAL)
panel = wx.Panel(self, -1)
self.list = wx.ListCtrl(panel, -1, style=wx.LC_REPORT)
self.list.InsertColumn(0, 'name', wx.LIST_FORMAT_CENTRE,width=140)
self.list.InsertColumn(1, 'place', wx.LIST_FORMAT_CENTRE,width=130)
self.list.InsertColumn(2, 'year', wx.LIST_FORMAT_CENTRE, 90)
for i in packages:
index = self.list.InsertStringItem(sys.maxint, i[0])
self.list.SetStringItem(index, 1, i[1])
self.list.SetStringItem(index, 2, i[2])
hbox.Add(self.list, 1, wx.EXPAND)
panel.SetSizer(hbox)
self.Centre()
self.Show(True)
app = wx.App()
Actresses(None, -1, 'actresses')
app.MainLoop()
I have found that this works (notice I start inserting the columns at 1 rather than 0):
self.list = wx.ListCtrl(panel, -1, style=wx.LC_REPORT)
self.list.InsertColumn(1, 'name', wx.LIST_FORMAT_CENTRE,width=140)
self.list.InsertColumn(2, 'place', wx.LIST_FORMAT_CENTRE,width=130)
self.list.InsertColumn(3, 'year', wx.LIST_FORMAT_CENTRE, 90)
Not sure why this works, but it does. Hopefully, there will be no repercussions from doing this.
Thanks to robots.jpg for inspiring the idea.
Windows definitely treats the first column differently. One workaround is to create an empty column 0 and hide it:
class Actresses(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(380, 230))
#...
self.list = wx.ListCtrl(panel, -1, style=wx.LC_REPORT)
self.list.InsertColumn(0, '', width=0)
self.list.InsertColumn(1, 'name', wx.LIST_FORMAT_CENTRE,width=140)
self.list.InsertColumn(2, 'place', wx.LIST_FORMAT_CENTRE,width=130)
self.list.InsertColumn(3, 'year', wx.LIST_FORMAT_CENTRE, width=90)
for i in packages:
index = self.list.InsertStringItem(sys.maxint, '')
self.list.SetStringItem(index, 1, i[0])
self.list.SetStringItem(index, 2, i[1])
self.list.SetStringItem(index, 3, i[2])
# catch resize event
self.list.Bind(wx.EVT_LIST_COL_BEGIN_DRAG, self.OnColDrag)
#...
def OnColDrag(self, evt):
if evt.m_col == 0:
evt.Veto()
I can't think of any major side-effects from doing this, but let me know if I'm wrong. I guess GetItemText() or anything else that assumes there is useful data in the first column would no longer be useful.
Edit - added code to prevent resizing column 0.
Related
I have built a graphic oriented package using the Graph element. I need to do keyboard input based on Graph Element coordinates. Currently I am using the events that come in from the keyboard to place characters on the Graph element using draw_text. It works but is a bit slow and I get into problems with interpreting the key codes I get back from different platforms and the overhead with me doing the echoing back on to the Graph element does not help.
My Question. In PySimpleGui(Tk) is there a way to use the Tk Entry function directly on Graph Coordinates?
IMO, it can be done like your request, but much complex.
Here only a simple way to enter text on a Graph element.
import PySimpleGUI as sg
font = ('Courier New', 16, 'bold')
layout = [
[sg.Input(expand_x=True, key='INPUT')],
[sg.Graph((320, 240), (0, 0), (320, 240), enable_events=True, key='GRAPH',
background_color='green')],
]
window = sg.Window('Draw Text', layout, margins=(0, 0), finalize=True)
entry, graph = window['INPUT'], window['GRAPH']
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event == 'GRAPH':
location, text = values['GRAPH'], values['INPUT']
if text:
graph.draw_text(text, location, font=font, color='white', text_location=sg.TEXT_LOCATION_LEFT)
window.close()
Here, something like your request, but much complex and tkinter code required.
import PySimpleGUI as sg
def entry_callback(event, graph, entry_id, font, location, color):
widget = event.widget
text = widget.get()
graph.widget.delete(entry_id)
if text:
graph.draw_text(text, location=location, font=font, color=color, text_location='sw')
font = ('Courier New', 16, 'bold')
layout = [
[sg.Graph((320, 240), (0, 0), (320, 240), enable_events=True, key='GRAPH',
background_color='green')],
]
window = sg.Window('Draw Text', layout, margins=(0, 0), finalize=True)
graph = window['GRAPH']
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event == 'GRAPH':
location = tuple(map(int, graph._convert_xy_to_canvas_xy(*values['GRAPH'])))
entry = sg.tk.Entry(graph.widget, font=font, fg='white', bg='green', width=45)
entry_id = graph.widget.create_window(*location, window=entry, anchor="sw")
entry.bind('<Return>', lambda event, graph=graph, entry_id=entry_id, font=font, location=values['GRAPH'], color='white':entry_callback(event, graph, entry_id, font, location, color))
entry.focus_force()
window.close()
so i want to make callback graph that can display the graph within theres two widget there (radio and selectbox), but i have some problem in here, the radio button (gender clasify) theres no change when i choose the gender, the graph still stay at same graph, and i want to input the selectbox with variable of the 'City' but theres somethin error message "DuplicateWidgetID"
this is my code:
with st.expander('Favorite product by Gender within city'):
column1, column2 = st.columns([3,1])
#Variables
#male_product = df[df['gender'] == 'Male'].groupby(['product_line','gender']).count()['quantity'].sort_values(ascending=False).reset_index()
#female_product = df[df['gender'] == 'Female'].groupby(['product_line','gender']).count()['quantity'].sort_values(ascending=False).reset_index()
#Callback
selected_gender = st.radio('What is your Gender:', ['Male', 'Female'], index = 0)
select_city = column2.selectbox('Select City', df.sort_values('City').City.unique())
male_product=px.histogram(df.sort_values('product_line') ,x='product_line', y='gross_income', color = 'product_line',)
female_product=px.histogram(df.sort_values('product_line') ,x='product_line', y='gross_income', color = 'product_line',)
if selected_gender == 'Male':
st.write('What men buy most!')
st.plotly_chart(male_product, use_container_width=True)
else:
st.write('What female buy most!')
st.plotly_chart(female_product, use_container_width=True)
and the display graph is
but theres will be error when i entry "select_city" to the code and theres will be notification like this:
thanks for your attention, and can someone help me.
This involves creating a dataframe with gender and city filters. I just created a sample data to demonstrate the solution.
Code
import streamlit as st
import plotly.express as px
import pandas as pd
data = {
'City': ['c1', 'c2', 'c3', 'c1', 'c3', 'c2', 'c1'],
'product_line': ['p1', 'p2', 'p3', 'p3', 'p2', 'p1', 'p4'],
'quantity': [8, 4, 3, 12, 5, 6, 4],
'gross_income': [250, 150, 300, 250, 300, 400, 500],
'gender': ['Male', 'Female', 'Male', 'Male', 'Female', 'Female', 'Male']
}
df = pd.DataFrame(data)
st.write(df)
with st.expander('Favorite product by Gender within city'):
column1, column2 = st.columns([3,1])
# Allow the user to select a gender.
selected_gender = st.radio('What is your Gender:', df.gender.unique(), index = 0)
# Apply gender filter.
gender_product = df[df['gender'] == selected_gender]
# Allow the user to select a city.
select_city = column2.selectbox('Select City', df.sort_values('City').City.unique())
# Apply city filter
city_gender_product = gender_product[gender_product['City'] == select_city]
# Use the city_gender_product dataframe as it has filters for gender and city.
fig = px.histogram(city_gender_product.sort_values('product_line') ,x='product_line', y='gross_income', color = 'product_line',)
if selected_gender == 'Male':
st.write('What men buy most!')
else:
st.write('What female buy most!')
st.plotly_chart(fig, use_container_width=True)
Output
1. Initial view or Male/city c1
2. Male/c3
3. Female/c2
I have a many2many field "tag_ids" both in models "news.ads" and "blog.post".
I want to get all the records from "blog.post" whose "tag_ids" exactly matches the "tag_ids" in "news.ads".
I tried the following in my controller but it doesn't worked,
blog_obj = request.registry['blog.post']
p_id = blog_obj.search(cr, uid, ['&', ['id','=',post_id], ['website_published', '=', True]], context=context)
post = blog_obj.browse(cr, uid, p_id, context=context)
ad_obj = request.registry['news.ads']
banner_ads = ad_obj.search(cr, uid, [('state', '=', 'publish'), ('tag_ids', 'in', [post.tag_ids])], context=context)
How do I search such records in odoo9? Any workaround..!!
with the old api, search already returns a list of id's of the matching records, so there is no need to call browse again, you can use the returned list directly in your domain filter
blog_obj = request.registry['blog.post']
p_id = blog_obj.search(cr, uid, ['&', ['id','=',post_id], ['website_published', '=', True]], context=context)
# post = blog_obj.browse(cr, uid, p_id, context=context) you don't need this
ad_obj = request.registry['news.ads']
banner_ads = ad_obj.search(cr, uid, [('state', '=', 'publish'), ('tag_ids', 'in', p_id)], context=context)
in the new api, which is highly recommended you'll have to go an extra step and extract the id's yourself because search now returns a record set
p_id = blog_obj.search(['&', ['id','=',post_id], ['website_published', '=', True]])
p_id = [p.id for p in p_id]
Note 1: DON'T USE OLD API IN ODOO-8 AND ODOO-9
First phase:
To get all the many2many id list we are using .ids it will return list.
Second phase:
Situation: We have two list, and you want to get items from second list, if they are in first list.
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> b
[2, 3, 5, 6, 7, 13]
>>> c = [x for x in b if x in a]
>>> c
[2, 3, 5, 6, 7]
Note 2: I'm odoo-8 developer.
Python/Django newcomer here. Im getting a syntax error with the following code, can anyone help me out here? IDLE3 highlights Line 16 "Treasure" just before ("Fool's Gold").
from django.shortcuts import render
# Create your views here.
def index(request):
return render(request, 'index.html', {'treasures':treasures})
class Treasure:
def __init__(self, name, value, material, location):
self.name = name
self.value = value
self.material = material
self.location = location
treasures = [
Treasure('Gold Nugget', 500.00, 'gold', "Curley's Creek, NM")
Treasure("Fool's Gold", 0, 'pyrite', "Fool's Falls, CO")
Treasure('Coffee Can', 20.00, 'tin', 'Acme, CA')
]
You forgot to put commas after the elements of the array. Like this:
treasures = [
Treasure('Gold Nugget', 500.00, 'gold', "Curley's Creek, NM"),
Treasure("Fool's Gold", 0, 'pyrite', "Fool's Falls, CO"),
Treasure('Coffee Can', 20.00, 'tin', 'Acme, CA')
]
class RangeSelection(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
layout = QGridLayout(self)
self.setLayout(layout)
self._create_widgets()
layout.addWidget(self.select_combo, 1, 1)
layout.addWidget(self.stacked, 1, 2, 5, 1)
self.stacked.currentWidget().setSizePolicy(
QSizePolicy.Preferred, QSizePolicy.Preferred)
self.stacked.currentChanged.connect(self.onCurrentChanged)
def onCurrentChanged(self):
currentw = self.stacked.currentWidget()
currentw.adjustSize()
if currentw == self.releasew:
currentw.sizeAdjustPolicy = QComboBox.AdjustToContentsOnFirstShow
self.adjustSize()
def _create_widgets(self):
self.stacked = QStackedWidget()
self.datew = QCalendarWidget()
self.datew.setVerticalHeaderFormat(QCalendarWidget.
NoVerticalHeader)
self.stacked.addWidget(self.datew)
self.buildidw = QLineEdit()
self.stacked.addWidget(self.buildidw)
self.releasew = QComboBox()
self.releasew.addItems([str(k) for k in sorted(releases())])
self.stacked.addWidget(self.releasew)
self.revw = QLineEdit()
self.stacked.addWidget(self.revw)
self.select_combo = QComboBox()
self.select_combo.addItems(['date', 'buildid', 'release', 'changeset'])
self.select_combo.activated.connect(self.stacked.setCurrentIndex)
I have this code where I am having four widgets in the QStackedWidget. When I run this code and change my selection in self.select_combo from date to release, the self.releasew combobox initially shows up as same size as that of the QCalendarWidget( which obviously looks horrible ). But, when I change my selection from release to any other value and then back to release, the self.releasew combobox shows up in the size it should. Why is this happening? What is the solution to this problem?
Note: I am using PyQt4. Also note that widgets for buildid and changeset do not show any abnormal behaviour.
I removed the setSizePolicy and sizeAdjustPolicy code. I also removed the call to self.adjustSize(). This worked. Though, I don't know why.