Закрыть без сохранения
2) Ещё было бы хорошо, чтобы пользователь при сохранении текущего файла не мог сохранить его под этим именем, а только под другим.
Суть в том, что есть файл Excel с макросами, содержание которого (файла) сохранять не нужно. Изменения могут производиться только в процессе работы с этим файлом, а сохранять их нельзя.
1) Хотелось бы узнать, как сделать так, чтобы при закрытии файла Excel программа не спрашивала пользователя "Сохранить изменения?", а сразу закрывала файл без сохранения?
ActiveWorkbook.Close savechanges:=False
ActiveWorkbook.Close savechanges:=False
Я поместил команду ActiveWorkbook.Close savechanges:=False в процедуру Workbook_BeforeClose. Теперь при закрытии файла программа не спрашивает "Сохранить изменения?" и закрывает без сохранения.
А как быть со вторым вопросом?
Я поместил команду ActiveWorkbook.Close savechanges:=False в процедуру Workbook_BeforeClose. Теперь при закрытии файла программа не спрашивает "Сохранить изменения?" и закрывает без сохранения.
А как быть со вторым вопросом?
попробуй вот так....может получится
ActiveWorkbook.SaveAs Filename:="Имя.xls"
ActiveWorkbook.Close savechanges:=True
попробуй вот так....может получится
ActiveWorkbook.SaveAs Filename:="Имя.xls"
ActiveWorkbook.Close savechanges:=True
Дмитрий,по-моему,эти команды можно применить при выполнении какого-то макроса. Я же хочу, чтобы при нажатии пользователем кнопки или меню "Сохранить", программа предлагала сохранить этот файл под другим именем, а под этим не разрешала вообще.
Как это сделать?
Дмитрий,по-моему,эти команды можно применить при выполнении какого-то макроса. Я же хочу, чтобы при нажатии пользователем кнопки или меню "Сохранить", программа предлагала сохранить этот файл под другим именем, а под этим не разрешала вообще.
Как это сделать?
к сожалению я еще не достиг такого уровння....
и каким образом можно перенастроить стандартные кнопки и команды не знаю....
единственный вариант это создать свою кнопку с такой-же иконкой, а стандартную убрать , если получится
Дмитрий,по-моему,эти команды можно применить при выполнении какого-то макроса. Я же хочу, чтобы при нажатии пользователем кнопки или меню "Сохранить", программа предлагала сохранить этот файл под другим именем, а под этим не разрешала вообще.
Как это сделать?
У тебя какая-то нетривиальная задачка, ты хочешь отобрать у пользователя возможность сохранения файла под тем же названием?
Тогда надо залезть в обработчик события Workbook_BeforeSave этой книги:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
SaveAsUi - True if the Save As dialog box will be displayed - наверное то что тебе нужно.
End Sub
У тебя какая-то нетривиальная задачка, ты хочешь отобрать у пользователя возможность сохранения файла под тем же названием?
Тогда надо залезть в обработчик события Workbook_BeforeSave этой книги:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
SaveAsUi - True if the Save As dialog box will be displayed - наверное то что тебе нужно.
End Sub
Да, Сергей, Вы правы: хочу отобрать у пользователя эту возможность. Но использование параметра SaveAsUi ничего не дало. Для того, чтобы пользователь не смог сохранить файл нужно сделать так
Cancel = True
тогда файл не сохраняется.
Самое смешное, что написав в обработчике событий выше приведенную команду я и сам теперь этот файл не могу сохранить, то есть не могу сохранить этот код ( Cancel=True )
Поэтому ничего не получается. Как быть?
Самое смешное, что написав в обработчике событий выше приведенную команду я и сам теперь этот файл не могу сохранить, то есть не могу сохранить этот код ( Cancel=True )
Поэтому ничего не получается. Как быть?
Попробуй открыть эту книгу ... отключить макросы...изменить нужную процедуру....и сохранить...должно получиться..... а вообще ситуация веселая :)
Ну пока можно в конце Cancel=False приписать, который все разрешит. Ну пока код не отработан, можно его еще тестить, а сохранять уже в самом конце.
Насчет SaveAsUi, это конечно не решит все проблемы, тут еще надо повозится с проверками, просто мне показалось что удобно будет использовать это уже готовую возможность.
Думаю логика должна быть такая (сходу, не проверяя, убегать уже пора :) )
1. Показываем диалог выбора сохранения файла (простой диалог, который возвращает токо имя и ничего больше не делает): Application.GetSaveAsFilename
2. Проверяем путь, если совпадает с текущим файлом - ругаемся на пользователя, куда-нибудь его посылаем или тихо игнорируем и ставим Cancel=True. Если путь не совпадает, то Cancel=False.
...
Думаю логика должна быть такая
1. Показываем диалог выбора сохранения файла (простой диалог, который возвращает токо имя и ничего больше не делает): Application.GetSaveAsFilename
2. Проверяем путь, если совпадает с текущим файлом - ругаемся на пользователя, куда-нибудь его посылаем или тихо игнорируем и ставим Cancel=True. Если путь не совпадает, то Cancel=False.
Вообщем сделал я следующее:
[COLOR=blue]
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim name, fName As String
name = "имя_файла.xls"
MsgBox "Рекомендуется сохранить файл под именем " + name, , "Внимание!"
ChDir ActiveWorkbook.Path
fName = Application.GetSaveAsFilename(InitialFileName:=name)
[color=green]'Если выбранное имя совпадает с именем текущего файла[/color]
If fName = ActiveWorkbook.FullName Then
[color=green]'Ругаемя на пользователя[/color]
MsgBox "Сохранение файла под текущим именем ЗАПРЕЩЕНО! Сохраниет файл под другим именем!", , "Внимание!"
Cancel = True [color=green]'отключаем сохранение[/color]
Else
[color=green]'иначе сохранение возможно[/color]
Cancel = False
[color=black]ПОСЛЕ ЭТОГО ФАЙЛ СОХРАНЯЕТСЯ ПОД ТЕКУЩИМ ИМЕНЕМ, А НЕ ПОД ТЕМ, КОТОРЫЙ ВЫБРАЛ ПОЛЬЗОВАТЕЛЬ!!! ВО КАК!!! ЧТО НУЖНО СДЕЛАТЬ, КАКОМУ ПАРАМЕТРУ ПРИСВОИТЬ ВЫБРАННОЕ ПОЛЬЗОВАТЕЛЕМ ИМЯ, ЧТОБЫ СОХРАНЕНИЕ ПРОИЗОШЛО КАК НАДО ???[/color]
End If
End Sub
[/COLOR]
Ещё обнаружил, что при вызове команды "Сохранить как" открывается стандартное окно сохранения, даже
[COLOR=blue]SaveAsUI = False[/COLOR]
не помогает. Вот блин, никак не могу как следует извратиться. Можно конечно просто запретить любое сохранение и всё.
Что посоветуете?
Сразу поясню насчет параметра SaveAsUI, чтоб он больше нам не мешал - эта переменная в событии _BeforeSave всего лишь показывает как пользователь пытается сохранить файл: серез СОХРАНИТЬ или через СОХРАНИТЬ КАК, и все. Это для информации, соотв. присвоение этой переменной какого своего значение внутри события _BeforeSave не имеет никакого смысла. Тебе Excel эту переменную передал в качестве информации, по ByVal к тому же и то что ей что то еще пытаешься присвоить, на это Excel уже никакого внимание обращать не будет.
Теперь на счет твоих проблем с SaveAs внутри события _BeforeSave.
Тут складывается действительно забавная ситуация. Дело в том, что вызывая метод в SaveAs в этом событии мы порождаем опять же это событие, поэтому очень важно предусмотреть возможность выхода из него, не допустив зацикливания.
Происходит все следующим образом:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
строка1
ThisWorkbook.SaveAs "c:\3.xls" ' строка2
строка3
End Sub
Мы нажимаем кнопку Сохранить в Excel'е.
попадаем в событие _BeforeSave на строчку1.
Переходим к строчке2 - ThisWorkbook.SaveAs "c:\3.xls", которая порождает ВТОРОЕ событие _BeforeSave.
Поэтому со строчки2 мы вновь попадаем на строчку1.
Визуально это можно представить себе так, как если разместить рядом два одниковых куска кода процедуры Private Sub Workbook_BeforeSave и нарисовать стрелку перехода со строчки2 первого куска на второй кусок Private Sub Workbook_BeforeSave.
Эта аналогия будет полной еще в том смысле, что Excel отработает весь второй кусок и потом, ВНИМАНИЕ: вернуться в первый кусок на след. строчку после той, с которой его грубо прервали вызвав SaveAs (т.е. в нашем примере на строчку3)
Т.е. выполнение кода по строчка будет следующее:
строчка1 (_BeforeSave1)
строчка2 (тут мы вызываем еще одно _BeforeSave)
строчка1 (_BeforeSave2)
'строчка2(_BeforeSave2)
строчка3 (_BeforeSave2)
строчка3 (вернeлись в первый _BeforeSave)
Хорошо видно что если не поставить какое-нибудь доп. условие на строчку2 (.SaveAs), то оно будет каждый раз порождает очередные _BeforeSave и мы так зациклимся.
Поэтому если внутри события _BeforeSave надо сохранить файл под другим названием, то бцдет например такой:
Dim bolEx As Boolean
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If lEvent = 0 Then
lEvent = 1
ThisWorkbook.SaveAs "c:\3.xls"
ElseIf lEvent = 1 Then
lEvent = 0
bolEx = True
End If
If lEvent = 0 And bolEx Then
bolEx = False
Cancel = False
Else
Cancel = True
End If
End Sub
Чтобы посмотреть как работает этот код можешь открыть приложенный файл поставить breakpoint на If lEvent = 0 Then в событии _BeforeSave и нажать кнопку сохранить и двигаясь по шагам (через F8 ) увидишь как для второго события устанавливается Cancel=False, а при возвращаении к первому Cancel становится равным =True (если этого не сделать, то получим зависание Excel'я, он будет пытаться сохранить файл, который мы уже сохранили под другим именем, у Excel крышу тогда снесет)
Хм, прикольная получилась задачка, я раз десять подвесил свой Excel, прежде чем во всем разобрался и отладил код :)
...вызывая метод в SaveAs в этом событии мы порождаем опять же это событие, поэтому очень важно предусмотреть возможность выхода из него, не допустив зацикливания.
Что происходит зацикливание, я сообразил, у меня тоже несколько раз подвисал Excel. Просто не знал как это обойти.
Большое спасибо тебе, Сергей. Я использую этот код, подредактирую и всё будет очень здорово! :)
А что значит на каждом листе такое начало:
[COLOR=blue]Option Explicit[/COLOR]
Это объявление глобальных переменных, которые будут видны во всех листах этой рабочей книги?
На самом деле я пытался просто объявить переменные в листе, чтобы из любой процедуры я мог иметь к ним доступ, но что-то у меня не вышло. Имя переменной доступно, а её значение оставалось нулевым или пустым.
Что происходит зацикливание, я сообразил, у меня тоже несколько раз подвисал Excel. Просто не знал как это обойти.
Большое спасибо тебе, Сергей. Я использую этот код, подредактирую и всё будет очень здорово! :)
А что значит на каждом листе такое начало:
[COLOR=blue]Option Explicit[/COLOR]
Это объявление глобальных переменных, которые будут видны во всех листах этой рабочей книги?
На самом деле я пытался просто объявить переменные в листе, чтобы из любой процедуры я мог иметь к ним доступ, но что-то у меня не вышло. Имя переменной доступно, а её значение оставалось нулевым или пустым.
А вот именно потому Option Explicit и нужно, чтобы не создавалось впечатления будто переменная доступна, но только нулевая.
Поясню:
Option Explicit - это директива в начале модуля с кодом означает - что все переменные требуют ОБЯЗАТЕЛЬНОГО объявления. Если переменная не была объявлена, но используется в коде, то возникнеи ошибка в процессе компиляции (т.е. еще до запуска программы)
Когда такой директивы Option Explicit нет, то компилятор Visual Basic работает в режиме, назовем его режимом "чайника-холявщика". Это когда компилятор встречая непознаную переменную просто объявляет ее в тихоря вместо тебя (на коде это не отражается, это происходит только в момент компиляции)
Типичный случай чем это плохо и почему надо всегда писать Option Explicit это твой пример.
Ты хотел объявить глобальную переменную, чтобы она была доступна везде внутри проекта. Для этого переменную нужно объявлять - обязательно в модуле (в обычном модуле) и Public.
Ты этого не знал и допустил ошибку, объявив свою переменную как Public НО внутри модуля листа. При этом твоя переменная НЕ СТАЛА доступной за пределами этого листа. При этом когда ты стал в блаженном неведении писать имя этой переменной в других модулях (в которых не стояло Option Explicit) компилятор не стал ругаться и спокойно тебе разрешил это сделать, он просто в тихоря создал еще одну локальную переменную в этом модуле. Именно поэтому она и была нулевой, потому что у тебя получилось две разные переменные, но с одинаковыми именами.
Если бы ты использовал бы Option Explicit, то компилятор бы сразу стал бы ругаться и эта ошибка не прошла бы у тебя незамеченной.
Чтобы не писать в начале каждого модуля - Option Explicit, достаточно поставить галку в Tools/Options - Require Variable Declaration (Требовать обязательного объявления) и в каждом новом модуле автоматом будет появляется эта строка.
Проверь свои входящие сообщения. ;) :roll: 8)