Распространенная ошибка.
string datetime = dataGridView1.Rows[i].Cells[2].Value.ToString();
Это неправильно! Если вы добавляете значения x в качестве строк, все они добавляются как 0
, а Series
не могут выровнять их с соответствующими слотами на оси X. Поэтому они добавляются слева направо последовательно.
Вместо этого просто добавьте x-значения в качестве DateTimes
, которые они должны быть!
Итак, если Cells
содержит DateTime
используются:
DateTime datetime = (DateTime) dataGridView1.Rows[i].Cells[2].Value;
Если они этого не делают, преобразуйте их в DateTime
DateTime datetime = Convert.ToDateTime(dataGridView1.Rows[i].Cells[2].Value);
. Для управления типом значений x установите XValueType
для каждой серии:
chart_dashboard.Series[yourSeries].XValueType = ChartValueType.DateTime;
Чтобы определить способ отображения этикеток оси, установите их форматирование:
chart_dashboard[ChartAreas[0].AxisX.LabelStyle.Format = someDateTimeFormatString;
Чтобы создать строку типа «Неделя 1», вы [
XValueType
на int16
..axis.LabelStyle.Format = "Week #0";
Чтобы извлечь номер из ваших данных, разделенных пробелом, и Convert.ToInt16!
Если вам действительно нужно вставлять разреженные значения x в виде строк, для вставки манекена DataPoint
в каждый промежуток в серии.
Создание манекена DataPoint
прост:
DataPoint dp = new DataPoint() { IsEmpty = true};
Но знание того, где пробелы заранее - это вызов! «Лучший» способ - передать данные и заполнить их перед добавлением очков. Или перейдите к нему позже, а не добавьте, вставив думмы в промежутки. И это гораздо больше проблем, чем получение данных в первую очередь!
Вы можете связывать полосы прокрутки только с несколькими виджетами, а корневой виджет и Frame
не являются частью этой группы виджетов.
Наиболее распространенное решение - создать виджет холста и связать полосы прокрутки с этим виджетами. Затем в этот холст встроен фрейм, содержащий виджеты ярлыков. Определите ширину / высоту кадра и отправьте это в параметр canvas scrollregion
, чтобы область прокрутки точно соответствовала размеру кадра.
Рисование текстовых элементов непосредственно на холсте не очень сложно , поэтому вы можете захотеть пересмотреть этот подход, если решение, встроенное в рамку в виде холста, кажется слишком сложным. Поскольку вы создаете сетку, координаты каждого текстового элемента будут очень легко вычисляться, особенно если каждая строка имеет одинаковую высоту (что, вероятно, это, если вы используете один шрифт).
Для рисования непосредственно на холсте просто определите высоту строки шрифта, который вы используете (и для этого есть команды). Тогда каждая координата y row*(lineheight+spacing)
. Координата x будет фиксированным числом, основанным на самом широком элементе в каждом столбце. Если вы дадите все тег для столбца, в котором он находится, вы можете настроить координату и ширину x всех элементов в столбце с помощью одной команды.
Вот пример решения, встроенного в рамку, с использованием объектно-ориентированного подхода:
import tkinter as tk
class Example(tk.Frame):
def __init__(self, root):
tk.Frame.__init__(self, root)
self.canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
self.frame = tk.Frame(self.canvas, background="#ffffff")
self.vsb = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side="right", fill="y")
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas.create_window((4,4), window=self.frame, anchor="nw",
tags="self.frame")
self.frame.bind("<Configure>", self.onFrameConfigure)
self.populate()
def populate(self):
'''Put in some fake data'''
for row in range(100):
tk.Label(self.frame, text="%s" % row, width=3, borderwidth="1",
relief="solid").grid(row=row, column=0)
t="this is the second column for row %s" %row
tk.Label(self.frame, text=t).grid(row=row, column=1)
def onFrameConfigure(self, event):
'''Reset the scroll region to encompass the inner frame'''
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
if __name__ == "__main__":
root=tk.Tk()
Example(root).pack(side="top", fill="both", expand=True)
root.mainloop()
Вот решение, которое не использует объекты :
import tkinter as tk
def populate(frame):
'''Put in some fake data'''
for row in range(100):
tk.Label(frame, text="%s" % row, width=3, borderwidth="1",
relief="solid").grid(row=row, column=0)
t="this is the second column for row %s" %row
tk.Label(frame, text=t).grid(row=row, column=1)
def onFrameConfigure(canvas):
'''Reset the scroll region to encompass the inner frame'''
canvas.configure(scrollregion=canvas.bbox("all"))
root = tk.Tk()
canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
frame = tk.Frame(canvas, background="#ffffff")
vsb = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True)
canvas.create_window((4,4), window=frame, anchor="nw")
frame.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))
populate(frame)
root.mainloop()
Примечание: чтобы эта работа выполнялась в python 2.x, используйте Tkinter
, а не tkinter
в инструкции import
Используйте этот удобный класс, чтобы прокручивать фрейм, содержащий ваши виджеты. Выполните следующие шаги:
import tkinter as tk
from tkinter import ttk
class Scrollable(ttk.Frame):
"""
Make a frame scrollable with scrollbar on the right.
After adding or removing widgets to the scrollable frame,
call the update() method to refresh the scrollable area.
"""
def __init__(self, frame, width=16):
scrollbar = tk.Scrollbar(frame, width=width)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y, expand=False)
self.canvas = tk.Canvas(frame, yscrollcommand=scrollbar.set)
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.config(command=self.canvas.yview)
self.canvas.bind('<Configure>', self.__fill_canvas)
# base class initialization
tk.Frame.__init__(self, frame)
# assign this obj (the inner frame) to the windows item of the canvas
self.windows_item = self.canvas.create_window(0,0, window=self, anchor=tk.NW)
def __fill_canvas(self, event):
"Enlarge the windows item to the canvas width"
canvas_width = event.width
self.canvas.itemconfig(self.windows_item, width = canvas_width)
def update(self):
"Update the canvas and the scrollregion"
self.update_idletasks()
self.canvas.config(scrollregion=self.canvas.bbox(self.windows_item))
root = tk.Tk()
header = ttk.Frame(root)
body = ttk.Frame(root)
footer = ttk.Frame(root)
header.pack()
body.pack()
footer.pack()
ttk.Label(header, text="The header").pack()
ttk.Label(footer, text="The Footer").pack()
scrollable_body = Scrollable(body, width=32)
for i in range(30):
ttk.Button(scrollable_body, text="I'm a button in the scrollable frame").grid()
scrollable_body.update()
root.mainloop()
<Configure>
, которое будет срабатывать при изменении размера холста. В обработчике событий вы можете настроить атрибутminsize
одного из столбцов, чтобы он заполнил весь холст (например:self.frame.columnconfigure(1, minsize=SIZE)
, где вы делаете небольшую математику для вычисления SIZE). – Bryan Oakley 13 May 2013 в 18:37<Configure>
самого холста, чтобы обрабатывать случай, когда он изменяется. – Bryan Oakley 8 April 2018 в 16:46