Ru-Board.club
← Вернуться в раздел «Прикладное программирование»

» Visual Basic 6

Автор: jek1976
Дата сообщения: 24.07.2009 19:55
dneprcomp
Вот, немного начинаю разбираться с БД. Спасибо.

А насчет использования транзакций не просветите? Я решил их использовать, т.к. информация, для хранения и обработки которой я делаю прогу, для меня очень ценна (это научный материал). Вот фрагмент кода:

Код: Private Sub Form_Load()

BasePath = "D:\Библиография\" 'путь к файлу БД
BaseName = "MainBase.mdb" 'файл БД

Set wks = DBEngine.Workspaces(0)
Set db = wks.OpenDatabase(BasePath + BaseName)
Set rsetSurname = db.OpenRecordset("Sprav_Authors", dbOpenDynaset)

End Sub

Private Sub Command1_Click()

wks.BeginTrans 'начало транзакции
rsetSurname.AddNew 'начало формирования записи
rsetSurname!Surname = Text1.Text 'добавление данных из текстового окна "Фамилия" (Text1)
rsetSurname!Name = Text2.Text 'добавление данных из текстового окна "Имя" (Text2)
rsetSurname!Patronymic = Text3.Text 'добавление данных из текстового окна "Отчество" (Text3)
rsetSurname.Update 'добавление сформированной записи в БД
rsetSurname.MoveNext 'переход на след. запись
wks.CommitTrans 'конец транзакции

End Sub
Автор: dneprcomp
Дата сообщения: 24.07.2009 20:51
jek1976
По логике кода все верно. Кроме строки rsetSurname.MoveNext. Она здесь не к месту.

Transaction нужны когда изменения происходят в нескольких table и важно сохранять данные в связи. К примеру, делаем update 2-x table последовательно. Первый прошел нормально. А вот на втором ошибка - данные не сохранились. Вот тут и сработает transaction и сделает undo всем изменениям в базе.
Возвращаясь к коду, в нем нехватает механизма on error. И wks.RoolbackTrans

Цитата:
А если начало и конец транзакции делать, соответственно, в начале и в конце ВСЕЙ программы?
Transaction используется только для работы с DB. Делать как в вопросе, все равно что начинать солить суп, когда в кастрюле не то, что супа, а еще воды то нет.
Цитата:
когда будет правильным начинать транзакцию, а когда правильным будет ее закончить?
А вот как сделал в коде, так и правильно. Как начинаем изменять данные в базе, так и пора BeginTrans. Как закончили данное конкретное изменение - CommitTrans. Как ошибка - RoolbackTrans.
В данном случае т.к. изменение происходит только в одном table, я бы не использовал транзакцию, а просто поставил бы errorhandler. До rsetSurname.Update изменений в базе еще нет. После - уже все записалось и без ошибки. Нет смысла в использовании транзакции.
Автор: jek1976
Дата сообщения: 24.07.2009 23:20
ОК, спасибо!
Автор: jek1976
Дата сообщения: 26.07.2009 00:47
dneprcomp
Еще такая ситуация.
Допустим, я добавил запись, состоящую из трех полей - Фамилия, Имя и Отчество, в таблицу БД методом .AddNew. Добавилась эта запись, конечно, в самый конец БД.
Но при таком добавлении происходит естественное нарушение сортировки фамилий в БД.
Как здесь поступить? Сортировать записи внутри самой БД (методом .Sort) или же отсортировать записи как-либо иначе?
Автор: dneprcomp
Дата сообщения: 26.07.2009 03:36
jek1976
Нет такого понятия как естественная сортировка. И запси далеко не всегда дбавляются в конец.
Физическое раположение в базе и представление данных на скрине или в репорте - совершенно разные и никак не связанные вещи. В 99% совершенно не интересно, как именно физически данные расположены в базе. Метод .Sort тоже не перемещает данные физически.
Сортируем или в рекордсете(order by field1, field2) или свойствами некоторых контролов(dropdownlist, grid)
Автор: jek1976
Дата сообщения: 26.07.2009 13:11
Понятно, спасибо.

Dneprcomp, я сделал вот таким образом:

Код: Public wks As Workspace
Public db As Database
Public rsetSurname As Recordset
Public rsetSurname1 As Recordset
Public rsetName As Recordset
Public КоличествоЗаписейТаблицы_Sprav_Authors As Long

Private Sub Form_Load()

BasePath = "D:\[Библиография]"
BaseName = "MainBase.mdb"

Set wks = DBEngine.Workspaces(0)
Set db = wks.OpenDatabase(BasePath + "\" + BaseName)
Set rsetSurname = db.OpenRecordset("Sprav_Authors", dbOpenDynaset)

End Sub

Private Sub Command1_Click()
Dim i As Long

rsetSurname.AddNew
rsetSurname!Surname = Text1.Text
rsetSurname!Name = Text2.Text
rsetSurname!Patronymic = Text3.Text
rsetSurname.Update
'выполняем сортировку записей внутри БД
Set rsetSurname1 = db.OpenRecordset("SELECT * " & "FROM Sprav_Authors ORDER BY Surname, Name", dbOpenDynaset)

Set rsetSurname = rsetSurname1


'обновление таблицы с "ФИО" на форме из таблицы "Sprav_Authors" БД:
'определяем кол-во записей в табл. "Sprav_Authors"
КоличествоЗаписейТаблицы_Sprav_Authors = rsetSurname.RecordCount
'устанавливаем кол-во строк в таблице на форме равным кол-ву записей
'в табл. "Sprav_Authors" (плюс одна строка для учета строки заголовка таблицы)
VSFlexGrid1.Rows = rsetSurname.RecordCount + 1
'переходим на первую запись в таблице "Sprav_Authors"
rsetSurname.MoveFirst
'перебираем все записи таблицы "Sprav_Authors"
For i = 1 To КоличествоЗаписейТаблицы_Sprav_Authors
'выводим номер текущей строки таблицы в нулевую (фиксированную) колонку
VSFlexGrid1.TextMatrix(i, 0) = Str(i)
'читаем фамилию из записи БД и переносим ее в таблицу на форме
VSFlexGrid1.TextMatrix(i, 1) = rsetSurname!Surname
'читаем имя из записи БД и переносим его в таблицу на форме
VSFlexGrid1.TextMatrix(i, 2) = rsetSurname!Name
'читаем отчество из записи БД и переносим его в таблицу на форме
VSFlexGrid1.TextMatrix(i, 3) = rsetSurname!Patronymic
'переходим на следующую запись в таблице "Sprav_Authors"
rsetSurname.MoveNext
Next i
Автор: dneprcomp
Дата сообщения: 26.07.2009 20:15
jek1976
В целом все верно.
1.Нехватает механизма обработки ошибок. К примеру, что будет с программой, если любое поле = Null ?
2. Нет смыла в строке rsetSurname.MoveFirst . Если никто recordset не трогал, он и так стоит на первой строке.
3.Гонять recordsrt movefirst, movelast cчитаеся не очень правильным с точки зреия потери ресурсов. Хорошо, база маленькая. Можно ведь и по другому:

Код: Do while not rsetSurname.eof
VSFlexGrid1.Rows = VSFlexGrid1.Rows + 1
VSFlexGrid1.TextMatrix(i, 2) = rsetSurname!Name
ну и т.д.

Loop
Автор: jek1976
Дата сообщения: 26.07.2009 23:53

Цитата:
К примеру, что будет с программой, если любое поле = Null ?

Null или "" ? Ведь поля-то текстовые!


Цитата:
Нет смыла в строке rsetSurname.MoveFirst . Если никто recordset не трогал, он и так стоит на первой строке.

А если придется несколько раз добавлять записи в таблицу при разных вызовах формы? Тогда рекордсет будет изменяться и каким он окажется в нужный момент?


Цитата:
Код:Do while not rsetSurname.eof
VSFlexGrid1.Rows = VSFlexGrid1.Rows + 1
VSFlexGrid1.TextMatrix(i, 2) = rsetSurname!Name
ну и т.д.
Loop

Этот код для того случая, когда рекордсет по умолчанию стоит на первой записи?


Цитата:
Цитата: Set rsetSurname = rsetSurname1
А это зачем?

Это старые куски - пробовал по-всякому изголяться. Этого уже нет в действительности.


Цитата:
Для чего на load открывается recordset?

Наверное, будет лучше открывать рекордсет ПРЯМО перед использованием базы??? И затем тут же закрывать после использования.




Автор: jek1976
Дата сообщения: 27.07.2009 03:19
И еще вопрос:
Вот две разных инициализации рекордсета:

Set БД = OpenDatabase(BasePath + "\" + BaseName)
Set Записи1 = БД.OpenRecordset("Sprav_Authors", dbOpenDynaset)

Set БД = OpenDatabase(BasePath + "\" + BaseName)
Set Записи2 = БД.OpenRecordset("SELECT * " & "FROM Sprav_Authors ORDER BY Surname, Name", dbOpenDynaset)

Не пойму, почему в первом случае кол-во записей в рекордсете Записи1 равно единице, а во втором случае, кол-во записей в рекордсете Записи2 равно реальному кол-ву записей, имеющихся в таблице "Sprav_Authors" (их там 137 штук)?
Автор: dneprcomp
Дата сообщения: 27.07.2009 05:40
jek1976
Null это не 0. Если поле не имеет дефолтного значения и полю еще не присваивали ничего, то его значение Null.

Цитата:
А если придется несколько раз добавлять записи в таблицу при разных вызовах формы? Тогда рекордсет будет изменяться и каким он окажется в нужный момент?

А кто обещал, что после добавления recordset автоматом покажет добавленные записи? Его еще рефрешать над. Или закрывать после использования.

Цитата:
Этот код для того случая, когда рекордсет по умолчанию стоит на первой записи?

Да.

Цитата:
Наверное, будет лучше открывать рекордсет ПРЯМО перед использованием базы??? И затем тут же закрывать после использования.
Обычно так и делают

Цитата:
почему в первом случае кол-во записей в рекордсете Записи1 равно единице, а во втором случае, кол-во записей в рекордсете Записи2 равно реальному кол-ву записей
А потому что в первом случае просто открыт table. Сколько в нем рекордов еще не известно. Да и вероятно будет всегда показывать 1 - т.е. текущий рекорд. Во втором же случае мы получили выборку. Количество строк тоже уже пощитано.
Автор: jek1976
Дата сообщения: 09.08.2009 14:07
dneprcomp
Спасибо.

На данный момент - принцип работы с БД более-менее понятен.
Сейчас работаю над интерфейсом проги. Суть в том, что надо отработать методику
Сначала возникла проблема в том, чтобы запомнить тот порядок, в каком пользователь выбирает фамилии, имена и отчества в таблице VSFlexGrid, перенесенные туда из БД. Важен именно порядок их выбора! Оказалось - это очень и очень непросто, т.к. можно выбирать как мышью, так и с помощью клавиатуры, а также в комбинации друг с другом. Кроме того, нужно учесть, что по некоторым выделенным ячейкам пользователь может щелкнуть повторно, сняв при это выделение. Эту затею с отслеживанием выделения строк мышью/клавиатурой в таблице VSFlexGrid - я оставил в покое - уж слишком много надо предусмотреть вариантов и код у меня стал очень объемным и трудночитаемым. Вместо этого пойду по другому пути.

Я решил преобразовать поля первой колонки таблицы VSFlexGrid в CheckBox'ы:
VSFlexGrid1.ColDataType(1) = flexDTBoolean.
Таким образом, необходимость выделения строк - отпадает и потребуется отслеживать лишь изменения состояния каждого из CheckBox'ов, связав его с соответствующей ячейкой одномерного массива (более подробнее обсуждать не буду - речь не об этом).

Вопрос, собственно, хочу задать совсем другой: как избавиться от точечной рамки выделения, которая появляется при щелчуе на ячейке (см. рис).




Автор: dneprcomp
Дата сообщения: 10.08.2009 07:34

Цитата:
Вопрос, собственно, хочу задать совсем другой: как избавиться от точечной рамки выделения, которая появляется при щелчуе на ячейке

Вопрос, собственно, хочу задать совсем другой: а кому и почему она мешает?
Это стандартный результат работы контрола.

Цитата:
запомнить тот порядок, в каком пользователь выбирает
И зачем такие сложности самому себе придумывать? Даже не могу себе представить ситуацию, когда это может понадобится.
Можно попробовать добавить еще одно поле в грид и в нем ставить номер по порядку. В самом грие, а не в массиве. Порядковый номер храним в переменной и добавляем 1 по мере выделения чекбокса. При снятии выдеоения просто очищаем поле. После окончания юзером селекта, прбегаем по гриду и заносим номера и другие данные в многомерный массив. Затем сортировка по номеру.
Полгаю что при таком подходе не понадобятся никакие алгоритмы выбора

PS.«Не следует множить сущее без необходимости». Ockham
Автор: jek1976
Дата сообщения: 10.08.2009 16:03

Цитата:
И зачем такие сложности самому себе придумывать? Даже не могу себе представить ситуацию, когда это может понадобится.

Программа, частью которой является обсуждаемая здесь проблема, предназначена для ведения библиографического каталога печатных и электронных изданий.
Ситуация очень проста: есть таблица (сделана на основе контрола VSFlexGrid) с ФИО авторов (книг, статей и проч.), данные в которую копируются из БД. Из этой таблицы необходимо выбрать авторов, размещая их в том порядке, в каком они перечислены в оригинале, т.е. на самом издании. Список авторов удобнее всего сформировать, просто щелкая на соответствующих строках таблицы с ФИО авторов, причем, сами понимаете, результат выстраивания ФИО авторов должен соответствовать тому порядку, в котором производились щелчки в этой самой таблице. Теперь понятно?




Добавлено:

Цитата:
Можно попробовать добавить еще одно поле в грид и в нем ставить номер по порядку. В самом грие, а не в массиве. Порядковый номер храним в переменной и добавляем 1 по мере выделения чекбокса. При снятии выдеоения просто очищаем поле. После окончания юзером селекта, прбегаем по гриду и заносим номера и другие данные в многомерный массив

Представьте себе юзера, которому надо будет так мудрить с расстановкой номеров, просто для того, чтобы выбрать список несчастных авторов!!! А если, выбрав несколько авторов путем расстановки номеров, юзер поймет, что первый автор не нужен, то ему что, заново перенумеровывать список? Ваше решение - неудачное для юзера, но простое для реализации программистом.
Что может быть проще для юзера, чем щелчки по нужным строкам в таблице авторов. Причем выстраивание авторов идет в том порядке, в котором производились щелчки - просто и понятно.
Но за такой простотой для пользователя скрывается сложность для программиста. А состоит она в том, что приходится учесть уж очень разные ситуации с выбором строк, такие как:
1) выделение диапазона смежных строк только при помощи мыши,
2) выделение диапазона смежных строк, производимое с нажатой клавишей Shift,
3) выделение несмежных строк (производимое с нажатой клавишей Ctrl),
4) неупорядоченное снятие выделения у одной или нескольких строк, включая строки, находящиеся внутри диапазона (т.к. юзер может ошибиться (промахнуться мимо) и щелкнуть не того или не тех авторов, которые нужны).

Код разрастается до больших размеров и при этом еще не реализована возможность учета снятия выделения строк. Я думал, в контроле VSFlexGrid должно быть реализовано нечто подобное, ведь в нем существует же перечислитель всех выделенных строк, о котором я упомянул выше.
Автор: dneprcomp
Дата сообщения: 10.08.2009 20:08
jek1976
Юзер не видит никаких номеров. И вообще не участвует в вычислении номера. Все делается автоматом. При условии использования чекбоксов.
Нам ведь не нужен ряд номеров без пропусков. Для сорта пойдет массив и с пропущенными номерами.
Кликнул - получил номер в невидимом столбце. Передумал, кликнул убрать чекбокс - удалили номер. Позже передумал, решил опять добавит - получил новый номер.
При таком подходе возможно этот "передуманный" автор окажется не на желаемом месте. Но IMHO реализация соответствует описанию.
Цитата:
Важен именно порядок их выбора!
Можно добавить ручную подсортировку, как 2-й необязательный шаг. Дать юзеру возможность менять позиции в листе(не в гриде). Как в любом download manager - передвинуть up or down
Автор: jek1976
Дата сообщения: 10.08.2009 23:38

Цитата:
При условии использования чекбоксов.

Ведь я об условии раньше уже сказал - это единственная разумная реализация поставленной задачи.
dneprcomp, вот как выглядит промежуточный рабочий вариант (значения в ячейках таблицы - с "потолка"):



Заодно удалось избавиться от рамки вокруг чекбокса.
Автор: dneprcomp
Дата сообщения: 11.08.2009 03:35
jek1976
Не понял каким образом определяется очередность выбора?

А ведь можно сделать еще интереснее. На каждое изменение чекбокса пересортировывать лист по невидимому полю с номерами. Так что сразу будет видна очередность авторов.
Автор: jek1976
Дата сообщения: 11.08.2009 03:41

Цитата:
А ведь можно сделать еще интереснее. На каждое изменение чекбокса пересортировывать лист по невидимому полю с номерами. Так что сразу будет видна очередность авторов.
Для этого логичнее будет перемещать записи с выбираемыми ФИО авторов - в другую таблицу. Если не сделать такого разделения на две таблицы, то будет каша...


Цитата:
Не понял каким образом определяется очередность выбора?
Код выложу, пока его еще не доделал.
Автор: dneprcomp
Дата сообщения: 11.08.2009 05:10
jek1976

Цитата:
Если не сделать такого разделения на две таблицы, то будет каша...
Не уверен, что будет. Пересортировка будет перемещать всю строку. Отсортировать можно по двум полям. Первое - по невидимому полю. Второе - по фамилии. Таким образом сверху вседа будут все отмеченные по порядку их выбора. А за ними все остальное по алфавиту.
Впрочем, хозяин - барин
Автор: jek1976
Дата сообщения: 11.08.2009 15:33
Добавил выделение цветом той строки, на которой поставлена галка в чекбоксе. В принципе - пока меня это удовлетворяет. Посмотрим далее, как это будет удобно/неудобно в работе.

Добавлено:
dneprcomp
Вопрос немного в сторону от темы.
Пусть имеется модуль, в котором организованы две процедуры - Proc1 и Proc2. В каждой из этих процедур объявлены (оператор Dim) по одной локальной переменной с одинаковыми именами.
Вопрос: эти две локальные переменные, находящиеся в разных процедурах, как-нибудь связаны друг с другом, то есть "знают" ли они о существовании друг друга?
Автор: dneprcomp
Дата сообщения: 11.08.2009 20:34

Цитата:
эти две локальные переменные, находящиеся в разных процедурах, как-нибудь связаны друг с другом, то есть "знают" ли они о существовании друг друга?

Нет, не знают
Автор: jek1976
Дата сообщения: 11.08.2009 21:58
Я тоже так думал.
Но! Если изменить написание идентификатора переменной в процедуре Proc1 (например, сделав буквы заглавными), то тут же изменится начертание идентификатора в процедуре Proc2. С чего бы это?
Автор: dneprcomp
Дата сообщения: 11.08.2009 23:14
jek1976
А это скорее всего значит, что где-то обявлена public с таким именем. Или dim в этом же модуле на высшем уровне.
Без кода такое не найти.
Кликни правой мышкой на имени переменной и выбери Definition. Сразу будет видно где объявлена.
Автор: jek1976
Дата сообщения: 12.08.2009 22:40
dneprcomp
Вот код модуля:

Код: Option Explicit

Sub Proc1()
Dim Abc As Integer

End Sub


Sub Proc2()
Dim Abc As Integer

End Sub
Автор: dneprcomp
Дата сообщения: 12.08.2009 23:00
jek1976
Да, действительно. Никогда не обращал внимания. Как-то не приходилось.
Так называемые, глюки обыкновенные... Или просто издержки внутреней реализации.
Но в любом случае, если в дебаге проследить, то переменная внутри sub равна 0 при старте Sub.
Т.е. уровень видимости переменых отслеживается четко.

Код:
'form
Private Sub Command1_Click()
MsgBox abc
abc = 13
MsgBox abc
Proc1
MsgBox abc
Proc1
MsgBox abc
End Sub
____________________________

'module
Option Explicit

Public abc As Integer

Sub Proc1()
Dim abc As Integer
MsgBox abc
End Sub


Sub Proc2()
Dim abc As Integer
MsgBox abc

End Sub
Автор: jek1976
Дата сообщения: 12.08.2009 23:22
Да, глюк. Хотя такого быть категорически не должно.
Этот глюк присутствует, если даже переменные - разные по сути, т.е., например, типа Integer и String, а не только Integer и Integer.
Автор: dneprcomp
Дата сообщения: 12.08.2009 23:46
jek1976
Но скоп все же работает. А это более важно.
Автор: jek1976
Дата сообщения: 12.08.2009 23:58
Согласен.
Автор: jek1976
Дата сообщения: 21.08.2009 02:20
dneprcomp
Приветствую! Давно я не был на форуме.

Есть две открытые формы. Сформировав (в полях TextBox, ComboBox и прочих) на одной из этих форм набор значений, состоящий из нескольких переменных (типа Integer и String), закрываем данную форму. Теперь возникает вопрос: каким образом при закрытии первой формы можно передать значения этих нескольких переменных второй форме? Наиболее очевидный вариант - передача с помощью заранее объявленных глобальных переменных - не рассматриваем. Есть ли еще какие-нибудь методы передачи (DDE и проч.), стабильные при использовании?
Автор: dneprcomp
Дата сообщения: 21.08.2009 03:54
jek1976
Привет, привет! А если бы меня здесь не стояло?
Ты так обращаешься, как будто подошел, а я тут на лавочке уже сижу


Цитата:
передача с помощью заранее объявленных глобальных переменных - не рассматриваем
А что ж так сурово? Можно ведь просто объявить public в модуле вместо global
Можно объявить во второй форме переменные как public и заполнять их из первой.
Можно заполнять какие-нибудь контролы на второй форме из первой.
Хочется экзотики вместо нормальных public в модуле - заносим значения хоть в реестр, хоть в ini.
Или просто по мылу с первой на вторую

Но учитывай, что при упоминании любого объекта или переменной его форма будет немеленно загружена и показана. А заодно oтработают все ивенты на загрузку.
Автор: jek1976
Дата сообщения: 21.08.2009 04:22

Цитата:
А если бы меня здесь не стояло?
Ты так обращаешься, как будто подошел, а я тут на лавочке уже сижу

Надеюсь, не обидел... Прости.


Добавлено:

Цитата:
Но учитывай, что при упоминании любого объекта или переменной его форма будет немеленно загружена и показана.

То есть если я из первой формы (активной, на которой есть "фокус") обращаюсь к свойству элемента второй формы (показанной на экране, но в данный момент - неактивной, т.е. без "фокуса"), то первая форма автоматом получит фокус и будет полностью показана на экране (к сожалению, самостоятельно это проверить временно не имею возможности)?

Страницы: 123456

Предыдущая тема: DrawGrid - заливка ячеек (Builder) ?


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.