Выбрать дату в календареВыбрать дату в календаре

Страницы: 1
Что влияет на работу Excel со скрытыми ячейками?, Где есть галочка, которая управляет способом обработки скрытых ячеек?
 
Никак не могу понять, что влияет на обработку скрытых ячеек? От файла к файлу поведение Excel'я со скрытыми ячейками разное:
  • - есть файлы, в которых Excel полностью игнорирует скрытые ячейки;
  • - а есть такие, где Excel обрабатывает скрытые ячейки наравне с видимыми.
Для примера прикладываю файл, в котором скрыта строка 9. Если выделить данные, захватив скрытую строку, и скопировать их, то данные будут обработаны, исключая скрытую строку. Но если мы вставим данные в диапазон, охватывающий скрытую строку, то вставка будет выполнена и в скрытые ячейки тоже. Двойные стандарты?!
Где есть та галочка, которая управляет способом обработки скрытых ячеек?
Организация контроля изменений в базе данных
 
Здравствуйте, дорогие форумчане!

Вопрос касается организации баз данных. Но поскольку вопрос является теоретическим, а реализовываться будет на VBA в Excel, я задаю его на этом форуме.

     Я разрабатываю небольшую систему учёта документов для организации. Всё уже работает, но захотелось иметь возможность контроля изменений и реализации отката этих изменений.
     Система работает на связке Excel-VBA + база данных Access, подключаемая через ADODB.
     Работа системы организована следующим образом:
1. по нажатии кнопки на Ribbon выводится таблица с данными из базы;
2. двойным кликом на строке вызывается форма редактирования  строки (Записи);
3. при нажатии на кнопку <Принять> на форме происходит фиксация изменений и обновление таблицы.

     На данном этапе при любом изменении Записи, Запись переписывается в базе данных, замещая старые данные:
Код
Dim rs As New ADODB.Recordset
….
    rs.Open ………..
    If rs.RecordCount > 0 Then
        rs.MoveFirst
        rs.Update ……….
        rs.UpdateBatch adAffectCurrent
    End If
    rs.Close
     Теперь хочу сделать так, чтобы при любом изменении Записи, она не переписывалась, а добавлялась новая Запись с тем же ключом, новым временем изменения (добавления) и пользователем, что внёс эти изменения. Пользователи всегда будут видеть только «последнее состояние записи».
     Звучит красиво и несложно, но возникает одно большое «но»: засорение базы многими копиями объекта и, как следствие, увеличение объёма базы
     Напрашивается необходимость принять правило, что надо удалять дублирующиеся Записи со сроком давности более, чем ХХХХ. Для этого необходимо периодически сканировать таблицы в базе данных для поиска таких Записей. Если при программировании на «взрослых» языках программирования можно выделить отдельный процесс, занимающийся таким важным делом, то на VBA придётся встраивать сканирование в основной процесс, замедляя основные операции.
     Прошу вас высказать своё мнение, подкинуть новую идею, дать совет по вариантам реализации и организации этого процесса.
Изменено: Skif-F - 26.07.2017 00:46:30
Список активных принтеров в Excel средствами VBA, список с возможностью применения для указания активного принтера
 
Занесла меня нелёгкая в необходимость выбора принтера через форму. Простейший поисковый запрос «как получить список принтеров в Excel» привёл меня к Игорю. Там я узнал, что имя принтера для Excel состоит из двух частей - непосредственно имени принтера и имени порта:
Код
sMyPrinterName= "Имя_принтера (Ne##:)" 'здесь ## - номер из двух цифр.
'И вот это имя передаётся Excel’ю, чтобы задать активный принтер:
Application.ActivePrinter = sMyPrinterName
WorkSheet. PrintOutActivePrinter:=sMyPrinterName 
Попытка применить полученные знания были пресечены Excel’ем на корню. Оказалось, что для необходимого мне принтера имя выглядело так:
“Имя_принтера (TPVM:)”
Где обещанные Ne##?!
Дальнейшие поиски привели к информации, что в скобочках указывается имя порта, но это имя не всегда совпадает с тем, что можно получить с помощью процедуры ВыводСвойствВсехПринтеров() с сайта Игоря. Тогда процедура была изменена, чтобы получить все свойства всех принтеров.
Код
Sub ВыводСвойствВсехПринтеров()
    Dim intPrinters As Integer
    Dim objWMIService As Object, colItems As Object, PRN As Object
    Dim PrpertiesAs Object, Prpt As Object
    Dim iAs Integer
    Dim txt As String
 
 
    intPrinters = 0
    Set objWMIService = GetObject("winmgmts://./root/CIMV2")
    Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Printer")
 
    For Each PRN In colItems 'Перебираем все принтеры в коллекции
        Set Prperties = PRN.Properties_
        i = 2
        For Each Prpt InPrperties  'Перебираем все свойства принтера
            With Prpt
               Cells(i, 1).Value = .Name                 'Имена свойств помещаем в первый столбец
               Cells(i, intPrinters + 2).Value = .Value  'Значения свойств размещаем в разных столбцах, начиная со второго
            End With
            i = i + 1
        Next Prpt
       intPrinters = intPrinters + 1
    Next PRN
End Sub
В результате прогона на разных системах (в том числе и на виртуальных машинах) с разными Офисами (от 2007 до 2016) и анализа полученных данных были сделаны следующие выводы:
  1. если свойство принтера «PrintJobDataType» равно «RAW», то применяется имя порта в формате "Ne##:";
  2. при значении «PrintJobDataType» равном «NT EMF 1.003» применяется имя порта, равное свойству «PortName» - в моём случае «PTVM:».
Поскольку верность этих утверждений осталась под сомнением, дальнейшие поиски привели на следующие странички:
stackoverflow.com и dailydoseofexcel.com

Из первой ссылки было выяснено, что формат имени принтера зависит ещё и от локализации!! Например, для англоязычной локализации имя принтера будет выглядеть так: “Printer_name on Port_Name:
Из второй ссылки получена идея взять номер порта из реестра. Там же предлагается для этого применять библиотеку regobj.dll, но поскольку данная библиотека не входит в комплект поставки Windows и требует отдельной установки, то доступ к реестру решено организовать через стандартный "WScript.Shell"

Всё это сложилось в следующий код:
Код
'Получаем список установленных в системе и подключенных принтеров
Function ВыводСпискаИмёнДоступныхПринтеров() as String()
    Dim objWMIService As Object, colItems As Object, PRN As Object
    Dim arr() As String, i As Long

    Set objWMIService = GetObject("winmgmts://./root/CIMV2")
    Set colItems = objWMIService.ExecQuery _
                   ("SELECT * FROM Win32_Printer WHERE PrinterStatus = '3'")
 
    ReDim arr(colItems.Count)
    i = -1
    'Перебираем все принтеры
    For Each PRN In colItems
        i = i + 1
       'Формируем имя принтера
       arr(i) = PRN.Name& " (" &PortNameFromReg(PRN.Name) & ")"
    Next PRN
    ВыводСпискаИмёнДоступныхПринтеров = arr
End Sub
 
'Получаем номер порта для указанного принтера
Function PortNameFromReg(ByVal PrnName As String) As String
    Dim objReg As Object
    Dim sKey As String, sPortName As String, arrSplt As Variant
 
    sKey = "HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Devices"
    Set objReg = CreateObject("WScript.Shell")
    'Сетевые принтеры имеют в составе имени «обратный слэш», который необходимо «спрятать»:
    'Считываем значение ключа
    'Если имя принтера содержит обратный слэш, тут будет выдана ошибка "Неверная ссылка на корень в разделе реестра ......."
    sPortName = objReg.RegRead(sKey& "\" & PrnName)
    If Len(sPortName) > 0 Then
        'Выделяем из значения имя порта
        arrSplt = Split(sPortName, ",")
        PortNameFromReg = arrSplt(UBound(arrSplt))
    Else
        PortNameFromReg = "неопределён"
    End If
End Function
Тут отсутствует обработка ошибок, поскольку не могу корректно обработать имя принтера "\\SKIF-PC\Canon iP2700 series". Пробовал слэш удваивать, заключать в кавычки и апострофы, ставить перед ним знак ^ - результат один: "Неверная ссылка на корень в разделе реестра ......."
Прошу помощи в решении вопроса: "Как через RegRead получить значение ключа реестра, если ключ содержит обратный слэш?"
Изменено: Skif-F - 03.02.2016 23:13:38
Тормоза беспроводных мыши и клавиатуры, Новая причина
 
Хочу поделиться с народом одним из решений давно наболевшей проблемы. Может, кому поможет сохранить немного нервов и времени.
Купил недавно себе беспроводной комплект Microsoft Wireless Desktop 800. Прихожу домой, подключаю и наблюдаю периодические лаги (тормоза) в работе мыши и клавиатуре. Попробовал на другом компьютере - работает нормально. Стал искать причину...
Поиск в сети предложил варианты:
  1. обновить драйверы;
  2. добавить ключи в реестр;
  3. обновить систему;
  4. устранить электромагнитные помехи (выключить Wi-Fi, убрать подальше сотовый телефон, разрушить радиостанцию соседа-радиста).
До пункта 2 руки дойти не успели (пишут, что чревато для системы), пункты 1 и 3 эффекта не дали. Соседа-радиста у меня нет, роутер отключен, сотовые убрал. В чём же причина?
И ведь нашёл! - HDMI кабель! Заменил сам шнурок и проложил его подальше от приёмника - мышь и клава работают, как часы!
Поэтому, столкнувшись с похожей проблемой, не забудьте проверить кабели и их расположение относительно приёмника. Так же рекомендую располагать приёмник не сзади корпуса, где высокий уровень помех, а спереди, хотя последнее чревато при наличии в доме маленьких детей
Ошибка Circular dependencies between modules, Причины возникновения ошибки
 
Столкнулся с ошибкой:
Цитата

Compile error:
Circular dependencies between modules
Проблема оказалась в следующем (всё лишнее выкинуто):
Есть модуль, где определены пользовательские типы "Типы":
Код
Public Type типДанные
    ТабНомер As Integer
    Объект As String
    ТипОбъ As enСистема  'Сюда идёт ссылка из класса Class1
End Type

Public Enum enAccessMode    'Сюда ссылаются интерфейс IClass и класс Class1
    Оператор = 0
    Администратор = 1
    Программист = 2
End Enum

Есть класс, описывающий интерфейс "IClass":
Код
'Модуль описывает интерфейс классов для хранения данных
'Вывести на экран форму для редактирования
Public Function Редактировать(ByVal Доступ As enAccessMode) As Variant: End Function

Есть рабочий класс "Class1" в котором используется интерфейс:
Код
Implements IClass 'Применяем интерфейс
Public Enum enСистема
    Особая = 3   
End Enum

Private Function IClass_Редактировать(ByVal Доступ As enAccessMode) As Variant 'Ошибка отображалась в этой строке
    IClass_Редактировать = FrmClass1.NewShow(Me, Доступ)
End Function

Пока не убрал определение перечисления enСистема из модуля класса в стандартный модуль, ошибка не пропала.
Похоже, что транслятор видел зацикленность определений между модулями. Отмечу, что другие классы, применяющие этот интерфейс, работают без проблем, но в них нет Public Enum. Ошибка проявилась только в Class1.
Вообще, прихожу к мнению, что все Public Enum и Public Type должны быть собраны в стандартном модуле, а в классах оставлять только скрытые определения.
Пример не прикладываю, поскольку это достаточно большая программа и вырывать кусок достаточно муторно.
Ввод данных на лист, не теряя управления формой
 
Имеется разветвлённая система "меню" (UserForm), на самом нижнем уровне необходимо ввести довольно большой объём данных. Логично реализовать это не через нагромождение Control'ов на форме, а подготовив рабочий лист.
Сложность в том, что при вызове формы в немодальном режиме - доступ к листу закрыт, а при вызове формы в модальном режиме - управление опять переходит к форме верхнего уровня, которая всё-равно немодальная.
Как вариант (см.вложение) держу управление в форме посредством цикла:
Код
Do Until НажалиНаКнопкуОкИлиОтмена        DoEventsLoop

Но что-либо делать на листе, когда крутится этот цикл невозможно.
Может быть кто сталкивался с подобной задачей и подскажет вариант решения?
Замена функции MultiCat в надстройке PLEX, Мой вариант функции слияния текста
 
Предлагаю заменить функцию MultiCat в надстройке PLEX на мой вариант.
Преимущества моего варианта:
   - работа с несколькими диапазонами, причём не только с непрерывными;
   - текстовыми строками;
   - числами (обрабатывая их как строки);
   - может работать в формулах массива.
Во вложении книга с функцией и примером.

Код
Function СУММСТРОК(Разделитель As String, ParamArray ДиапазонИлиТекст()) As String
    'Суммирует значения, заданные в виде ячеек, диапазонов ячеек, строковых и числовых констант,
    'складывая строковые значения и размещая их через Разделитель
    'Предназначена для вызова из листа
    'Может работать в формулах массива
    Dim x, Y, temp3 As String, temp2 As String
    temp2 = ""
    For Each x In ДиапазонИлиТекст
        If IsObject(x) Then
            If TypeName(x) = "Range" Then
                If x.Count > 1 Then
                    For Each Y In x
                        temp3 = СУММСТРОК(Разделитель, Y)
                        If temp2 <> "" Then
                            If Len(temp3) > 0 Then
                                'Mid(temp3, 1, 1) = LCase(Mid(temp3, 1, 1))
                                temp2 = temp2 + Разделитель + temp3
                            End If
                        Else
                            temp2 = temp3
                        End If
                        temp3 = ""
                    Next Y
                Else
                    temp3 = CStr(x.Value)
                End If
            End If
        ElseIf IsArray(x) Then
            For Each Y In x
                temp3 = СУММСТРОК(Разделитель, Y)
                If temp2 <> "" Then
                    If Len(temp3) > 0 Then
                        'Mid(temp3, 1, 1) = LCase(Mid(temp3, 1, 1))
                        temp2 = temp2 + Разделитель + temp3
                    End If
                Else
                    temp2 = temp3
                End If
                temp3 = ""
            Next Y
        Else
            Select Case TypeName(x)
                Case "String"
                    temp3 = x
                Case "Integer", "Long", "Single", "Double"
                    temp3 = CStr(x)
            End Select
        End If
        If temp2 <> "" Then
            If Len(temp3) > 0 Then
                'Mid(temp3, 1, 1) = LCase(Mid(temp3, 1, 1))
                temp2 = temp2 + Разделитель + temp3
            End If
        Else
            temp2 = temp3
        End If
    Next x
    СУММСТРОК = temp2
End Function
Страницы: 1
Наверх