Я просто нашел огромную утечку памяти, таким образом, я собираюсь назвать код, который создал утечку, чтобы быть неправильный и моя фиксация, которая не протекает как право .
Вот старый код: (Это - общий шаблон, который я видел на всем протяжении)
class Singleton {
static Singleton getInstance() {...}
void addListener(Listener listener) {...}
void removeListener(Listener listener) {...}
}
class Leaky {
Leaky() {
// If the singleton changes the widget we need to know so register a listener
Singleton singleton = Singleton.getInstance();
singleton.addListener(new Listener() {
void handleEvent() {
doSomething();
}
});
}
void doSomething() {...}
}
// Elsewhere
while (1) {
Leaky leaky = new Leaky();
// ... do stuff
// leaky falls out of scope
}
Очевидно, это плохо. Многие Leaky создается и никогда не собирается "мусор", потому что слушатели поддерживают их.
Здесь была моя альтернатива, которая зафиксировала мою утечку памяти. Это работает, потому что я только забочусь о слушателе события, в то время как объект существует. Слушатель не должен поддерживать объект.
class Singleton {
static Singleton getInstance() {...}
void addListener(Listener listener) {...}
void removeListener(Listener listener) {...}
}
class NotLeaky {
private NotLeakyListener listener;
NotLeaky() {
// If the singleton changes the widget we need to know so register a listener
Singleton singleton = Singleton.getInstance();
listener = new NotLeakyListener(this, singleton);
singleton.addListener(listener);
}
void doSomething() {...}
protected void finalize() {
try {
if (listener != null)
listener.dispose();
} finally {
super.finalize();
}
}
private static class NotLeakyListener implements Listener {
private WeakReference<NotLeaky> ownerRef;
private Singleton eventer;
NotLeakyListener(NotLeaky owner, Singleton e) {
ownerRef = new WeakReference<NotLeaky>(owner);
eventer = e;
}
void dispose() {
if (eventer != null) {
eventer.removeListener(this);
eventer = null;
}
}
void handleEvent() {
NotLeaky owner = ownerRef.get();
if (owner == null) {
dispose();
} else {
owner.doSomething();
}
}
}
}
// Elsewhere
while (1) {
NotLeaky notleaky = new NotLeaky();
// ... do stuff
// notleaky falls out of scope
}
Вот код для этого, но здесь есть одна загвоздка.
Private Sub Command1_Click()
Dim i As Long
Dim RS As Recordset
Dim F As Form
Set F = Me.sf.Form
Set RS = F.RecordsetClone
If F.SelHeight = 0 Then Exit Sub
' Move to the first selected record.
RS.Move F.SelTop - 1
For i = 1 To F.SelHeight
MsgBox RS![myfield]
RS.MoveNext
Next i
End Sub
Вот загвоздка: Если код добавлен к кнопке, как только пользователь нажимает эту кнопку, выбор теряется в сетке (высота будет равна нулю). Поэтому вам нужно захватить эту информацию и сохранить ее в переменной уровня модуля с помощью таймера или других событий в форме.
Вот статья, в которой подробно описывается, как обойти уловку.
http://www.mvps.org/access/forms/frm0033.htm
Уловка 2: Это только работает с непрерывным выделением. Они не могут выбрать несколько непоследовательных строк в сетке.
Обновление:
Может быть более удачное событие, чтобы отловить это, но вот рабочая реализация с использованием свойства form.timerinterval, которое я тестировал (на по крайней мере в Access 2k3, но 2k7 должен работать нормально)
Этот код входит в ПОДФОРМУ, используйте свойство, чтобы получить значение selheight в главной форме.
Public m_save_selheight As Integer
Public Property Get save_selheight() As Integer
save_selheight = m_save_selheight
End Property
Private Sub Form_Open(Cancel As Integer)
Me.TimerInterval = 500
End Sub
Private Sub Form_Timer()
m_save_selheight = Me.selheight
End Sub
Я использовал технику, аналогичную JohnFx
. Чтобы зафиксировать высоту выделения до того, как она исчезнет, я использовал событие Exit элемента управления подчиненной формы в основной форме.
Итак, в основной форме :
Private Sub MySubForm_Exit(Cancel As Integer)
With MySubForm.Form
m_SelNumRecs = .SelHeight
m_SelTopRec = .SelTop
m_CurrentRec = .CurrentRecord
End With
End Sub
Я пробовал делать что-то подобное раньше, но у меня никогда не получалось использовать метод, который требовал, чтобы пользователь выбирал несколько строк в том же стиле, что и диалоговое окно Windows File (нажатие Ctrl, Shift и т. Д.)
Один из методов, который я использовал, - это использование двух списков. Пользователь может дважды щелкнуть элемент в левом окне списка или нажать кнопку, когда элемент выбран, и он переместится в правое окно списка.
Другой вариант - использовать локальную таблицу, которая заполняется вашим источником данные плюс логические значения, представленные в виде флажков в подчиненной форме. После того, как пользователь выбирает, какие данные ему нужны, щелкая по флажкам, пользователь нажимает кнопку (или какое-либо другое событие), после чего вы переходите непосредственно к базовой таблице данных и запрашиваете только те строки, которые были отмечены. Считаю этот вариант лучшим, хотя для правильной работы требуется немного кода.
Даже в Access мне иногда легче работать с таблицами и запросами напрямую, чем пытаться использовать встроенные инструменты в формах Access. Иногда встроенные инструменты не делают именно то, что вам нужно.