How to set height for listbox
Hi,
I'm trying to make a template for a two pane file manager, but I can't seem to stretch the listbox all the way down.
I have -
import ctypes, platform
import dearpygui.dearpygui as dpg
from subprocess import Popen, PIPE
dpg.create_context()
dpg.set_global_font_scale(3)
# dpg.show_style_editor()
if platform.system() == "Windows":
user32 = ctypes.windll.user32
screen_width, screen_height = user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)
elif platform.system() == "Linux":
output = Popen('xrandr | grep "\*" | awk \'{print $1}\'',shell=True, stdout=PIPE).communicate()[0]
resolution = output.strip().split(b'x')
screen_width, screen_height = int(resolution[0]), int(resolution[1].split(b'\n')[0])
else:
screen_width, screen_height = 800, 600
dpg.create_viewport(title='Custom Title', width=screen_width, height=screen_height)
with dpg.window(label='Dual Pane File Manager', width=screen_width, height=screen_height):
with dpg.group(): #optional group for better layout
dpg.add_text('Left Panel')
with dpg.child_window(width=screen_width // 2, height = screen_height - 40):
listbox_tag = dpg.generate_uuid()
listbox = dpg.add_listbox(items=('check', '1', '2', '3', '4'),
tag=listbox_tag)
# dpg.set_item_height(listbox, screen_height - 40)
# dpg.set_item_height(listbox_tag, screen_height - 40)
dpg.setup_dearpygui()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()
It seems that listbox doesn't support height, and I was unable to make dpg.set_item_height() work either.
Is there a way to make a listbox use up all the height available by its container?
Thanks, Eli
Hi,
There is lisbox's paramenter: num_items.
I would specify width and num_items in a listbox,
then specify
autosize in window
and auto_resize_x, auto_resize_y in child_window.
import dearpygui.dearpygui as dpg
dpg.create_context()
dpg.create_viewport()
with dpg.window(autosize=True):
with dpg.group():
dpg.add_text("Left Panel")
with dpg.child_window(auto_resize_x=True, auto_resize_y=True):
dpg.add_listbox(items=("0 - check", "1", "2", "3", "4"), num_items=10, width=300)
dpg.setup_dearpygui()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()
Much obliged, using num_items makes the listbox fan out height-wise.
Could you perhaps advise - trying to add navigation using the up and down arrow. I got -
import dearpygui.dearpygui as dpg
selected_index = 0
def on_key_press(sender, data):
global selected_index
if dpg.is_key_pressed(dpg.mvKey_Up) and selected_index > 0:
# dpg.set_item_focus(listbox, selected_index - 1)
selected_index -= 1
dpg.set_value(listbox_tag, items[selected_index])
elif dpg.is_key_pressed(dpg.mvKey_Down) and selected_index < dpg.get_item_count(listbox) - 1:
# dpg.set_item_focus(listbox, selected_index + 1)
selected_index += 1
dpg.set_value(listbox_tag, items[selected_index])
screen_width, screen_height = get_screen_resolution()
dpg.create_context()
dpg.set_global_font_scale(3)
dpg.create_viewport(width=screen_width, height=screen_height)
items = 'check', '1', '2', '3', '4'
with dpg.window(label='Dual Pane File Manager', height=screen_height,):
with dpg.group():
dpg.add_text('Left Panel')
with dpg.child_window(width=screen_width // 2):
listbox = dpg.add_listbox(items=items, num_items=30,
default_value=items[selected_index], callback=on_key_press)
# dpg.add_key_press_handler(callback=on_key_press)
dpg.setup_dearpygui()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()
Can't seem to get the arrow keys to work for navigating the listbox. What am I missing?
I think dpg.is_key_pressed/released are meant to be used with handler/item_handler,
except is_key_down can be queried in normal callback.
import dearpygui.dearpygui as dpg
dpg.create_context()
dpg.create_viewport()
listbox_tag = dpg.generate_uuid()
items = ["0 - check", "1", "2 - second", "3", "4"]
def listbox_cb(s, a, u):
print(f"holding LControl: {dpg.is_key_down(dpg.mvKey_LControl)}, listbox value: {dpg.get_value(listbox_tag)}")
# def listbox_focused_cb(s, a, u): # mouse down at the listbox
# def listbox_key pressed-released-down ...
def listbox_visible_cb(s, a, u):
listbox_cfg = dpg.get_item_configuration(listbox_tag)
num_items = listbox_cfg["num_items"]
curr_val = dpg.get_value(listbox_tag)
idx = items.index(curr_val)
if not dpg.is_item_hovered(listbox_tag):
return
else: # doing something even the listbox not focusing
pass
if dpg.is_key_down(dpg.mvKey_LControl):
if dpg.is_key_released(dpg.mvKey_E): # increasing listbox height
# (not ideal) or is_key_down that it will call several frames
dpg.configure_item(listbox_tag, num_items=num_items + 1)
# listbox_cb(s, a, u)
if dpg.is_key_released(dpg.mvKey_Q): # decreasing listbox height
dpg.configure_item(listbox_tag, num_items=num_items - 1)
# listbox_cb(s, a, u)
if dpg.is_item_hovered(listbox_tag):
len_items = len(items)
if dpg.is_key_released(dpg.mvKey_Up):
decrease = idx - 1
if decrease + 1 == 0:
return
dpg.configure_item(listbox_tag, default_value=items[decrease])
listbox_cb(s, a, u)
if dpg.is_key_released(dpg.mvKey_Down):
increase = idx + 1
if increase + 1 > len_items:
return
dpg.configure_item(listbox_tag, default_value=items[increase])
listbox_cb(s, a, u)
# # better remove this section, use normal callback.
# # because it prints previous frame value.
# if dpg.is_mouse_button_clicked(dpg.mvMouseButton_Left) and dpg.is_item_hovered(listbox_tag):
# listbox_cb(s, a, u)
# dpg.split_frame()
# print(f"left clicked! listbox selected: {dpg.get_value(listbox_tag)}")
with dpg.window(autosize=True):
with dpg.group():
dpg.add_text("Left Panel")
with dpg.child_window(auto_resize_x=True, auto_resize_y=True):
dpg.add_listbox(
items=items,
default_value="2 - second",
callback=listbox_cb, # above concern
num_items=10,
width=300,
tag=listbox_tag,
)
with dpg.item_handler_registry() as listbox_handler_reg:
dpg.add_item_visible_handler(callback=listbox_visible_cb)
dpg.bind_item_handler_registry(listbox_tag, listbox_handler_reg)
dpg.setup_dearpygui()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()
Again, much obliged!
Managed to make up / down work based on your example -
import dearpygui.dearpygui as dpg
dpg.create_context()
dpg.set_global_font_scale(3)
screen_width, screen_height = get_screen_resolution() # Omitted for brevity
dpg.create_viewport(width=screen_width, height=screen_height)
items = 'check', '1', '2', '3', '4'
with dpg.window(label='Dual Pane File Manager', height=screen_height,):
with dpg.group():
dpg.add_text('Left Panel')
with dpg.child_window(width=screen_width // 2):
listbox_tag = dpg.generate_uuid()
listbox = dpg.add_listbox(items=items, num_items=30, default_value='check', tag=listbox_tag)
listbox_cfg = dpg.get_item_configuration(listbox)
# Up / Down arrow scrolling
def listbox_scroll_cb(s, a, u):
idx = items.index(dpg.get_value(listbox))
if dpg.is_key_released(dpg.mvKey_Up):
if idx < 1:
return
dpg.configure_item(listbox, default_value=items[idx - 1])
if dpg.is_key_released(dpg.mvKey_Down):
if idx > len(items) -2:
return
dpg.configure_item(listbox, default_value=items[idx + 1])
with dpg.item_handler_registry() as listbox_handler_reg:
dpg.add_item_visible_handler(callback=listbox_scroll_cb)
dpg.bind_item_handler_registry(listbox, listbox_handler_reg)
dpg.setup_dearpygui()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()
I had to remove the if dpg.is_item_hovered(listbox): pre-condition, as this would only let me scroll when the mouse was already over one of the items.
How to set height without using num_items as that value could be variable ?
@IvRogoz,
with dpg.window(label="demo", autosize=True):
dpg.add_listbox(("A","B","C"),tag="listbox")
# might need to define separate callback instead of lambda for replacing
# user_data with your dict["abcxyz"] or class_instance.variable_abcxyz,
dpg.add_button(
label="increase listbox's height",
user_data=3, # default num_items of listbox if not specified in listbox above
callback=lambda sender, app_data, user_data: [
dpg.configure_item("listbox", num_items=user_data+1),
dpg.set_item_user_data(sender, user_data+1)
]
)
default_height = 90 # it will become 80 =4*20 as num_items=4 fits in 90
dpg.add_button(
label="reset listbox's height",
callback=lambda s, a, u: dpg.configure_item("listbox", num_items=int(default_height/20)),
# the number 20 might vary if you change something relate to its text (font, size. padding...)
# TODO: modify the previous button's user_data
)
Thank you. It works but its not the same as having a height=-1 regardless of number of items.
@IvRogoz, In that case, you need to get the height or rect_size of listbox's parent (group, child_window, window,...), for computing the listbox's num_items.
or make your own that comprise a child_window(height=-1), checkboxes, selectable,...
I met such a problem as well. I cannot set a height to listbox. I follow here.
DPG uses ImGui::ListBox https://github.com/hoffstadt/DearPyGui/blob/d3577817fa69d6b5a8b56fde023b0200c0ff83ef/src/mvBasicWidgets.cpp#L4365
Which originates from
https://github.com/ocornut/imgui/blob/139e99ca37a3e127c87690202faec005cd892d36/imgui_widgets.cpp#L8152-L8197
ImGui::ListBox seem abstracted away the ImGui::BeginListBox() that the size is distinguished (height_in_items vs frame_bb)
https://github.com/ocornut/imgui/blob/139e99ca37a3e127c87690202faec005cd892d36/imgui_widgets.cpp#L8105-L8110
https://github.com/ocornut/imgui/issues/8194
Also, notice the float height_in_items_f = height_in_items + 0.25f;
It explains why you will have redundant pixels at the bottom (num_items=33, there redundant of 33*0.25=8.25 pixels)
For me, it kind of mutually exclusive: num_items and height can't be used altogether. If there is height param, we have to ditch num_items (that someone comfortably using)?
@IvRogoz, In that case, you need to get the height or rect_size of listbox's parent (group, child_window, window,...), for computing the listbox's num_items.
or make your own that comprise a child_window(height=-1), checkboxes, selectable,...
https://github.com/ocornut/imgui/blob/139e99ca37a3e127c87690202faec005cd892d36/imgui_widgets.cpp#L8091
Also, notice the
float height_in_items_f = height_in_items + 0.25f;It explains why you will have redundant pixels at the bottom (num_items=33, there redundant of 33*0.25=8.25 pixels)
I was wrong about a point, It actually 33.25 plus redundant,
The redundant at the bottom of listbox is because of + g.Style.FramePadding.y * 2.0f
https://github.com/ocornut/imgui/blob/139e99ca37a3e127c87690202faec005cd892d36/imgui_widgets.cpp#L8162